Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nodejs 的微服务概念 #210

Open
yaogengzhu opened this issue Nov 21, 2024 · 0 comments
Open

Nodejs 的微服务概念 #210

yaogengzhu opened this issue Nov 21, 2024 · 0 comments

Comments

@yaogengzhu
Copy link
Owner

示例代码
以下是使用 Seneca 构建微服务架构的示例代码,包括用户服务、商品服务、订单服务、库存服务和网关服务。

用户服务

// userService.js
const Seneca = require('seneca');

const userService = Seneca();

let users = [];

userService.add({ role: 'user', cmd: 'register' }, (msg, reply) => {
  const { username, password } = msg;
  if (!username || !password) {
    return reply(null, { error: 'Username and password are required' });
  }
  const user = { id: users.length + 1, username, password };
  users.push(user);
  reply(null, user);
});

userService.add({ role: 'user', cmd: 'login' }, (msg, reply) => {
  const { username, password } = msg;
  const user = users.find(u => u.username === username && u.password === password);
  if (!user) {
    return reply(null, { error: 'Invalid username or password' });
  }
  reply(null, { success: true, userId: user.id });
});

userService.listen({ type: 'http', port: 3001, pin: 'role:user' });

商品服务

// productService.js
const Seneca = require('seneca');

const productService = Seneca();

let products = [];

productService.add({ role: 'product', cmd: 'create' }, (msg, reply) => {
  const { name } = msg;
  if (!name) {
    return reply(null, { error: 'Product name is required' });
  }
  const product = { id: products.length + 1, name };
  products.push(product);
  reply(null, product);
});

productService.listen({ type: 'http', port: 3002, pin: 'role:product' });

订单服务

// orderService.js
const Seneca = require('seneca');

const orderService = Seneca();

let orders = [];

orderService.add({ role: 'order', cmd: 'create' }, (msg, reply) => {
  const { userId, productId } = msg;
  if (!userId || !productId) {
    return reply(null, { error: 'User ID and Product ID are required' });
  }

  orderService.act({ role: 'user', cmd: 'get', id: userId }, (err, user) => {
    if (err || !user) {
      return reply(null, { error: 'Invalid User ID' });
    }

    orderService.act({ role: 'product', cmd: 'get', id: productId }, (err, product) => {
      if (err || !product) {
        return reply(null, { error: 'Invalid Product ID' });
      }

      const order = { id: orders.length + 1, userId, productId };
      orders.push(order);
      reply(null, order);
    });
  });
});

orderService.listen({ type: 'http', port: 3003, pin: 'role:order' });

库存服务

// inventoryService.js
const Seneca = require('seneca');

const inventoryService = Seneca();

let inventory = [];

inventoryService.add({ role: 'inventory', cmd: 'update' }, (msg, reply) => {
  const { productId, quantity } = msg;
  if (!productId || quantity === undefined) {
    return reply(null, { error: 'Product ID and Quantity are required' });
  }
  const item = inventory.find(i => i.productId === productId);
  if (item) {
    item.quantity = quantity;
  } else {
    inventory.push({ productId, quantity });
  }
  reply(null, { success: true });
});

inventoryService.listen({ type: 'http', port: 3004, pin: 'role:inventory' });

网关服务

// gatewayService.js
const Seneca = require('seneca');
const express = require('express');
const bodyParser = require('body-parser');

const app = express();
app.use(bodyParser.json());

const gatewayService = Seneca();

gatewayService.client({ type: 'http', port: 3001, pin: 'role:user' });
gatewayService.client({ type: 'http', port: 3002, pin: 'role:product' });
gatewayService.client({ type: 'http', port: 3003, pin: 'role:order' });
gatewayService.client({ type: 'http', port: 3004, pin: 'role:inventory' });

app.post('/api/:role/:cmd', (req, res) => {
  const { role, cmd } = req.params;
  const msg = { role, cmd, ...req.body };
  gatewayService.act(msg, (err, result) => {
    if (err) {
      return res.status(500).json({ error: err.message });
    }
    res.json(result);
  });
});

app.listen(3000, () => {
  console.log('Gateway service listening on port 3000');
});

请求示例
以下是如何通过 HTTP 请求调用网关服务的示例。

URL: http://localhost:3000/api/user/register

  1. 请求方法: POST
  2. 请求体: {"username":"testuser","password":"testpass"}
  3. 头部: Content-Type: application/json
  4. 这个请求会被网关服务接收,并转发到用户服务的注册处理器。

URL: http://localhost:3000/api/user/login

  1. 请求方法: POST
  2. 请求体: {"username":"testuser","password":"testpass"}
  3. 头部: Content-Type: application/json
  4. 这个请求会被网关服务接收,并转发到用户服务的登录处理器。

说明
网关服务使用 Express 框架接收 HTTP 请求,并通过动态路由和模式匹配将请求转发到相应的微服务。
请求通过 HTTP POST 方法发送到网关服务的 /api/:role/:cmd 路径,网关服务接收到请求后,通过 Seneca 的 act 方法将请求转发到相应的微服务,并返回结果。
通过这种方式,可以简化网关服务的维护,并且更容易扩展。每次新增接口时,只需要在相应的微服务中添加处理器,而不需要修改网关服务。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant