Nestjs 微服务实战 - 动态微服务创建链接

这篇具有很好参考价值的文章主要介绍了Nestjs 微服务实战 - 动态微服务创建链接。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

所有的微服务都需要做服务治理

服务治理包括(配置中心、服务发现、注册服务等等),常见的包括 Java 的 Nacos,这里不关注与服务治理,只说明,如何用 nest 网关,并且在网关层动态实现微服务注入

nestjs 官网的案例明显是偏向于手动注册微服务的,例如:

/** Model */
@Module({
  imports: [
 	/** Model 中使用并注册 */ 
    ClientsModule.register([
      { name: 'MATH_SERVICE', transport: Transport.TCP },
    ]),
  ]
  ...
});

/** service / controller 使用 */
constructor(
  /** 通过 @Inject 装饰器只能挨个进行倒入,有多少服务倒入多少 */
  @Inject('MATH_SERVICE') private client: ClientProxy,
) {}

以上属于官网列出的例子,对于真正的微服务开发肯定是不够用的,因为服务并没有根据配置中心的配置进行动态变更倒入,这种情况下,假如某个服务很占用 CPU、内存导致荡机了,也无法进行动态扩展,只能去重启服务手动更改配置,而我需要的是完全动态,每个服务部署都独立部署出来,对于高CPU的服务进行动态扩展服务器,进行自动切换 ip 端口线路。

首先所有的服务都不要在 Model 中进行注册,建议全丢在 service / controller 中使用,我这里以 controller 为例:

import { All, Controller, Req, Res } from '@nestjs/common';
import { ClientProxyFactory, Transport } from '@nestjs/microservices';
import { createProxyServer } from 'http-proxy';

/** 动态数组,这里后面要通过定时任务去配置中心拉取 */
const serviceList = [
  {
    name: 'user-center',
    host: '127.0.0.1',
    port: 65531,
  },
];

@Controller()
export class AppController {
  /** 首先所有路由不管任何请求方式全部代理到这个方法上 */
  @All('*')
  async root(@Req() req, @Res() res): Promise<any> {
    /** 获取所有可获取的参数 */
    const { method, originalUrl, query, body, headers } = req;

    /** 根据 url 字符串切割一下获取,主要获取第一级和第二级路由 */
    const list = originalUrl.split('?')[0].split('/').filter((item: string) => item !== '');

    /** 所有,开头为 /api 的参数,并且路由大于并且等于 2 级以上的,基本都可以调用微服务 */
    if (list.length >= 2 && list[0] === 'api') {
    
      /** 微服务真正的地址,是三级路径 */
      const path = `/${list.slice(2).join('/')}`;

      /** 服务名称是二级目录 */
      const service = list[1];

      /** 查找服务名称是否存在 */
      const server = serviceList.find((item) => item.name === service);

      /** 服务存在 */
      if (server) {
      
        /** 错误执行 */
        const errorNext = (err: string) => {
          /** 地址错误 */
          if (err === 'There is no matching message handler defined in the remote service.') {
            /** 手动关闭服务链接 */
            this[service].close();
            /** 清楚链接,下次链接如果服务可用就触发重新链接 */
            this[service] = undefined;
            
            res.status(404);
            res.send({
              code: -1,
              msg: '地址错误',
            });
            
          } else {
            console.log(`其他错误: ${err}`);
          }
        };
        /** 当前 class 中找不到服务,需要创建服务 */
        if (!this[service]) {
          /** 动态创建服务链接 */
          this[service] = ClientProxyFactory.create({
            transport: Transport.TCP,
            options: {
              host: server.host,
              port: server.port,
            },
          });
          try {
            /** 链接服务 */
            await this[service].connect();
            /** 发送消息*/
            const data = this[service].send(
              /** 服务的接口地址是 { method = 请求方法, path = 等于相对路径 }  */
              { method, path },
              /** 把所有 http 的参数全部传递过去,让那边服务自己判断处理 */
              { query, body, headers },
            );
            /** 接受流消息 */
            data.subscribe({
              /** 成功执行 next */
              next: (_res_: any) => {
                res.status(200);
                res.send(_res_);
              },
              /** 失败吧错误信息丢个 errorNext */
              error: (err: any) => errorNext(err),
            });
          } /** 服务存在,但是可能荡机了,又或者服务正在重启过程中 */ catch (err) {
            /** 手动关闭服务链接 */
            this[service].close();
            /** 清楚链接,下次链接如果服务可用就触发重新链接 */
            this[service] = undefined;
            res.status(503);
            res.send({
              code: -1,
              msg: '当前服务正在维护中',
            });
          }
        } /** 服务已存在 */ else {
          /** 发送消息*/
          const data = this[service].send(
            /** 服务的接口地址是 { method = 请求方法, path = 等于相对路径 }  */
            { method, path },
            /** 把所有 http 的参数全部传递过去,让那边服务自己判断处理 */
            { query, body, headers },
          );
          /** 接受流消息 */
          data.subscribe({
            /** 成功执行 next */
            next: (_res_: any) => {
              res.status(200);
              res.send(_res_);
            },
            /** 失败吧错误信息丢个 errorNext */
            error: (err: any) => errorNext(err),
          });
        }
      } /** 未找到服务 */ else {
        res.status(404);
        res.send({
          code: -1,
          msg: '未找到对应的服务',
        });
      }
    } /** 反向代理到 admin 地址 */ else if (list.length >= 2 && list[0] === 'admin') {
      const proxy = createProxyServer({
        target: 'http://127.0.0.1:4000',
        changeOrigin: true,
      });
      proxy.on('error', () => {
        res.status(503);
        res.send({
          code: -1,
          msg: '当前服务正在维护中',
        });
      });
      proxy.web(req, res);
    } /** 反向代理到 nuxt ssr 前端页面地址 */ else {
      const proxy = createProxyServer({
        target: 'http://127.0.0.1:5000',
        changeOrigin: true,
      });
      proxy.on('error', () => {
        res.status(503);
        res.send({
          code: -1,
          msg: '当前服务正在维护中',
        });
      });
      proxy.web(req, res);
    }
  }
}

以上是我的核心逻辑部分,主要逻辑应该是一下步骤,文章来源地址https://www.toymoban.com/news/detail-819697.html

/** 1、创建服务 */
const proxy = ClientProxyFactory.create({
  transport: Transport.TCP,
  options: {
    host: '127.0.0.1',
    port: 65531,
  },
});

/** 2、服务连接 */
await proxy.connect();

/** 3、发送消息 */
const data = this[service].send(
  消息接口,
  附加数据,
);

/** 4、接受流消息 */
data.subscribe({
  /** 成功消息 */
  next: (_res_: any) => {
    res.status(200);
    res.send(_res_);
  },
  /** 排错 */
  error: (err: any) => {},
});

到了这里,关于Nestjs 微服务实战 - 动态微服务创建链接的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringCloudAlibaba微服务实战系列(一)Nacos服务注册发现

    实战前先做一个背景了解。 单体架构:近几年技术的飞速发展,各种各样的服务已经进入到网络化。单体架构发布时只需要打成一个war或jar包发布即可;而随着业务量激增或网站流量的增加,必会暴露致命缺陷。 SOA:Service Oriented Architecture 面向服务的体系结构。旨在提升代

    2024年02月15日
    浏览(37)
  • 《微服务实战》 第三十二章 微服务链路跟踪-sleuth zipkin

    第三十二章 微服务链路跟踪-sleuth zipkin 第三十章 分布式事务框架seata TCC模式 第二十九章 分布式事务框架seata AT模式 第十二章 Spring Cloud Alibaba Sentinel 第十一章 Spring Cloud Alibaba nacos配置中心 第十章 SpringCloud Alibaba 之 Nacos discovery 第七章 Spring Cloud 之 GateWay 第六章 Spring Cloud 之

    2024年02月09日
    浏览(41)
  • go-zero微服务实战——etcd服务注册与发现

    浅谈etcd服务注册与发现 etcd官网 etcd中文文档 apt安装etcd,启动命令十分简单 etcd 。 etcd分为v2版本和v3版本,命令有所不一样,使用命令 etcdctl h 查看 如上图所示并没有出现API的版本,此时是使用默认的v2版本,但是v2版本很多命令使用不了,因此切换为v3版本,命令如下: e

    2024年02月12日
    浏览(39)
  • [golang gin框架] 40.Gin商城项目-微服务实战之Captcha验证码微服务

    本次内容需要 gin框架基础知识, golang微服务基础知识才能更好理解 在前面,讲解了微服务的架构等,这里,来讲解前面商城项目的 Captcha验证码 微服务 ,captcha验证码功能在前台,后端 都要用到 ,可以把它 抽离出来 ,做成微服务功能 编辑 这个验证码功能封装代码captcha.go如下: 把这个

    2024年02月16日
    浏览(44)
  • [golang gin框架] 42.Gin商城项目-微服务实战之后台Rbac微服务角色增删改查微服务

    上一节讲解了后台Rbac微服务用户登录功能以及Gorm数据库配置单独抽离,Consul配置单独抽离,这一节讲解 后台Rbac微服务 角色 增删改查微服务 功能,Rbac微服务角色增删改查微服务和 后 台Rbac用户登录微服务 是属于 同一个Rbac微服务 的 不同子微服务功能 ,为了区分不同子微

    2024年02月15日
    浏览(41)
  • [golang gin框架] 45.Gin商城项目-微服务实战之后台Rbac微服务之角色权限关联

    角色和权限的关联关系在前面文章中有讲解,见[golang gin框架] 14.Gin 商城项目-RBAC管理之角色和权限关联,角色授权,在这里通过微服务来实现 角色对权限的授权 操作,这里要实现的有两个功能,一个是进入授权,另一个是,授权提交操作,页面如下:  这里需要在proto/rbacRole.proto中增加

    2024年02月14日
    浏览(57)
  • [golang gin框架] 44.Gin商城项目-微服务实战之后台Rbac微服务之权限的增删改查微服务

    上一节讲解了[golang gin框架] 43.Gin商城项目-微服务实战之后台Rbac微服务之管理员的增删改查以及管理员和角色关联,这里讲解权限管理Rbac微服务权限的增删改查微服务 要实现权限的增删改查,就需要创建对应的模型,故在server/rbac/models下创建Access.go模型文件,参考[golang gin框架]

    2024年02月14日
    浏览(43)
  • SpringCloud微服务实战——搭建企业级开发框架:微服务安全加固—自定义Gateway拦截器实现防止SQL注入/XSS攻击

     SQL注入是常见的系统安全问题之一,用户通过特定方式向系统发送SQL脚本,可直接自定义操作系统数据库,如果系统没有对SQL注入进行拦截,那么用户甚至可以直接对数据库进行增删改查等操作。   XSS全称为Cross Site Script跨站点脚本攻击,和SQL注入类似,都是通过特定方

    2024年02月03日
    浏览(65)
  • 【node.js从入门到精通】使用express创建web服务器,路由,进行中间件的创建链接路由及其他中间件

    目录 前言 初识express 使用express创建基本的web服务器 初识express路由 路由匹配概念 路由模块化 中间件 中间件和路由的区别 定义中间件函数 中间件作用   局部生效中间价 中间件分类  1.应用级别中间件  2.路由级别的中间件  3.错误级别中间件  4.内置中间件  5.自定义中间

    2024年02月02日
    浏览(55)
  • 【微服务实战之Docker容器】第四章-【微服务实战之Docker容器】第三章-镜像仓库

    【微服务实战之Docker容器】第一章-下载及安装 Docker挂载主机目录访问如果出现cannot open directory .: Permission denied解决办法: 在挂载目录后多加一个–privileged=true参数即可 如果是CentOS7安全模块会比之前系统版本加强,不安全的会先禁止,所以目录挂载的情况被默认为不安全的

    2024年02月07日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包