大家好,欢迎回来,
今天,我们将介绍微服务应用程序的第二部分 - 单个服务的代码。
为了快速回忆起first part,我们今天要制造的服务是:
- 产品:用于列出和搜索产品。
- 订单:用于下订单。这是受验证服务器的保护
- 通知:用于在发布新订单时通知用户。
- auth:在下订单之前用于检查用户身份验证。
所以,没有更多的延迟,让我们开始
ps:此处的代码不完整,对于完整的代码,请查看Github repo
产品服务
这将是一个简单的节点,表达REST API。有一个GET
端点可以列出所有产品。代码就像:
const express = require('express');
const app = express();
app.get('/', (req, res, next) => {
const { ids } = req.query;
let resultProducts = products;
if (ids) {
const productIds = ids.split(',');
resultProducts = products.filter((p) => {
return productIds.includes(p.id));
}
}
res.status(200).json(resultProducts);
});
您会注意到我们有一个名为ids
的查询参数。我们将使用它来获取所有产品的子集。
此外,为简单起见,完整的产品列表来自本地变量here。
订单服务
这也是一个节点,即表示REST API,但不像产品那样简单。仍然只有一个POST
端点,但是由于它做了多件事,让我们看一下代码。
首先,我们从请求主体中提取userId
和productIds
,然后使用productIds
从产品服务中获取更多产品详细信息(主要是价格和名称):
const { productIds, userId } = req.body;
const { data: orderedProducts } = await axios.get(
`${PRODUCTS_APP_HOST}/?ids=${productIds.join(',')}`
);
然后,我们计算产品的订单和逗号分隔的名称列表:
let totalAmount = 0;
let orderedProductNames = '';
for (const product of orderedProducts) {
totalAmount += product.price;
orderedProductNames += orderedProductNames === '' ? product.name : `, ${product.name}`
}
最后,我们发布了nats-broker
的消息(我们下一步将查看Notification Service),然后将响应发送给API请求。与产品服务类似,这里也没有数据库,因此我们只返回一个带有随机ID的普通JSON对象。
natsClient.sendMessage(
NEW_ORDER_MESSAGING_CHANNEL,
`Hello ${userId}, your order is confirmed. Products: ${orderedProductNames}`
);
res.status(201).json({
productIds,
totalAmount,
userId,
id: Math.floor(Math.random() * 9999)
});
通知服务
此服务是NATS订户,聆听发布给“新订单放置频道”的消息。目前,我们只是将传入的消息记录到控制台,但是在现实世界中,我们可以通过短信,电子邮件等通知用户。
该代码由2个函数组成,一个是消息的处理程序,另一个是启动订户的处理程序。
function handleMessages(err, message) {
if (err) {
console.log(`Error while reading messages: ${err}`);
return;
}
console.log(`Message received on channel "${NEW_ORDER_MESSAGING_CHANNEL}"`);
console.log(message);
}
async function main() {
await natsClient.startup();
natsClient.subscribe(NEW_ORDER_MESSAGING_CHANNEL, handleMessages);
}
main().catch(console.log);
nats-client
代码
这是一个通用文件,可以由想要与Nats经纪人交谈的任何服务使用。
const { connect, StringCodec } = require('nats');
const NATS_BROKER_URL = process.env.NATS_BROKER_URL;
class NatsClient {
#conn;
#codec;
constructor() {
this.#codec = StringCodec();
}
async startup() {
this.#conn = await connect({ servers: NATS_BROKER_URL });
console.log(`Connected to nats broker on "${this.#conn.getServer()}"`);
}
sendMessage(channel, message) {
this.#conn.publish(
channel,
this.#codec.encode(message)
);
}
subscribe(channel, cb) {
this.#conn.subscribe(channel, {
callback: (err, payload) => {
cb(err, this.#codec.decode(payload.data))
}
});
console.log(`Subscribed to messaging channel "${channel}"`);
}
}
当前,订单服务使用sendMessage
方法,通知服务使用subscribe
方法。
验证服务
这再次是REST API。但是,只是为了将其混合一点,它是使用FastAPI框架内置的。当前,只有一个端点可以验证Authorization
标头,该标头检查是否有硬编码的令牌值。
@app.get("/verify")
def verify_token(authorization: Annotated[str | None, Header()] = None):
if authorization != "secret-auth-token":
return JSONResponse(
status_code=status.HTTP_401_UNAUTHORIZED,
content=None
)
return JSONResponse(
status_code=status.HTTP_200_OK,
content=None
)
包起来
这就是单个服务代码的全部。在下一部分中,我们将查看root Level docker-compose.yml
文件和nginx.conf
文件以启动应用程序的所有组件并使事情正常工作。
我希望您会喜欢这个系列并学习新知识。
随时在下面的评论中发布任何问题。
欢呼!