16-网关-自研微服务框

网关

在这里插入图片描述

在微服务的场景下,服务因为分布在不同的服务器上,但是用户在访问的时候,不可能去维护这成百上千的入口,希望有统一的入口来进行访问,这就是网关的作用。

网关最重要的一个功能就是路由功能,能将请求转发到具体的业务服务器上

1. 简单实现

httputil.ReverseProxy 定义了一组方法让使用者去实现,主要有这几个

  • Director
    最核心的方法, 我们可以在这里对请求进行相应的修改,比如设置请求目标的地址,对原有请求头进行增删改,以及对请求体进行处理等等操作。

  • ModifyResponse
    可以让我们对响应的结果进行处理,比如修改、读取响应头和响应体。

  • ErrorHandler
    请求出错或者ModifyResponse返回error时会回调该方法,比如目标服务器无法连接,请求超时等等

package mainimport ("github.com/mszlu521/msgo""github.com/mszlu521/msgo/gateway"
)func main() {engine := msgo.Default()engine.OpenGateWay = truevar configs []gateway.GWConfigconfigs = append(configs, gateway.GWConfig{Name: "order",Path: "/order/**",Host: "127.0.0.1",Port: 9003,}, gateway.GWConfig{Name: "goods",Path: "/goods/**",Host: "127.0.0.1",Port: 9002,})engine.SetGateConfigs(configs)engine.Run(":80")
}
package gatewaytype GWConfig struct {Name stringPath stringHost stringPort int
}
package gatewayimport "strings"type TreeNode struct {Name     stringChildren []*TreeNodeIsEnd    boolGwName   string
}func (t *TreeNode) Put(path string, gwName string) {root := tstrs := strings.Split(path, "/")for index, v := range strs {if index == 0 {continue}children := t.ChildrenisMatch := falsefor _, node := range children {if node.Name == v {isMatch = truet = nodebreak}}if !isMatch {isEnd := falseif index == len(strs)-1 {isEnd = true}treeNode := &TreeNode{Name: v, Children: make([]*TreeNode, 0), IsEnd: isEnd, GwName: gwName}children = append(children, treeNode)t.Children = childrent = treeNode}}t = root
}//返回最后匹配的节点
func (t *TreeNode) Get(path string) *TreeNode {strs := strings.Split(path, "/")for index, v := range strs {if index == 0 {continue}children := t.ChildrenisMatch := falsefor _, node := range children {if node.Name == v ||node.Name == "*" ||strings.Contains(node.Name, ":") {isMatch = truet = nodeif index == len(strs)-1 {return node}break}}if !isMatch {//没匹配的情况下 检查是否有**for _, node := range children {if node.Name == "**" {return node}}return nil}}return nil
}
type Engine struct {*routerfuncMap          template.FuncMapHTMLRender       render.HTMLRenderpool             sync.PoolLogger           *msLog.LoggerglobalMiddles    []MiddlewareFuncerrorHandler     ErrorHandlerOpenGateWay      boolgatewayTreeNode  *gateway.TreeNodegatewayConfigMap map[string]gateway.GWConfig
}

func (e *Engine) handleHttpRequest(ctx *Context) {if e.OpenGateWay {//网关业务处理uri := ctx.R.URL.Pathnode := e.gatewayTreeNodematchNode := node.Get(uri)if matchNode == nil {ctx.W.WriteHeader(http.StatusNotFound)fmt.Fprintln(ctx.W, ctx.R.RequestURI+" not found")return}gwConfig := e.gatewayConfigMap[matchNode.GwName]target, _ := url.Parse(fmt.Sprintf("http://%s:%d%s", gwConfig.Host, gwConfig.Port, uri))director := func(req *http.Request) {req.Host = target.Hostreq.URL.Host = target.Hostreq.URL.Path = target.Pathreq.URL.Scheme = target.Schemeif _, ok := req.Header["User-Agent"]; !ok {req.Header.Set("User-Agent", "")}}response := func(response *http.Response) error {log.Println("改变返回值")return nil}handler := func(writer http.ResponseWriter, request *http.Request, err error) {log.Println("错误处理", err)}proxy := httputil.ReverseProxy{Director: director, ModifyResponse: response, ErrorHandler: handler}proxy.ServeHTTP(ctx.W, ctx.R)return}//....
}

2. 支持Header设置

if gwConfig.Header != nil {gwConfig.Header(req)}

用户在配置中指定其要设置的请求Header即可

3. 支持注册中心

有过前面的经验,这里就比较简单,设置注册中心名称,然后获取host和port的时候去注册中心获取即可


func (e *Engine) handleHttpRequest(ctx *Context) {if e.OpenGateWay {//网关业务处理uri := ctx.R.URL.Pathnode := e.gatewayTreeNodematchNode := node.Get(uri)if matchNode == nil {ctx.W.WriteHeader(http.StatusNotFound)fmt.Fprintln(ctx.W, ctx.R.RequestURI+" not found")return}gwConfig := e.gatewayConfigMap[matchNode.GwName]if gwConfig.OpenRegister {if e.register == "nacos" {client := e.registerClient.(naming_client.INamingClient)instance, err := client.SelectOneHealthyInstance(vo.SelectOneHealthInstanceParam{ServiceName: gwConfig.Name,})if err != nil {panic(err)}gwConfig.Host = instance.IpgwConfig.Port = int(instance.Port)}}target, _ := url.Parse(fmt.Sprintf("http://%s:%d%s", gwConfig.Host, gwConfig.Port, uri))director := func(req *http.Request) {req.Host = target.Hostreq.URL.Host = target.Hostreq.URL.Path = target.Pathreq.URL.Scheme = target.Schemeif _, ok := req.Header["User-Agent"]; !ok {req.Header.Set("User-Agent", "")}if gwConfig.Header != nil {gwConfig.Header(req)}}response := func(response *http.Response) error {log.Println("改变返回值")return nil}handler := func(writer http.ResponseWriter, request *http.Request, err error) {log.Println("错误处理", err)}proxy := httputil.ReverseProxy{Director: director, ModifyResponse: response, ErrorHandler: handler}proxy.ServeHTTP(ctx.W, ctx.R)return}
}

type Engine struct {*routerfuncMap          template.FuncMapHTMLRender       render.HTMLRenderpool             sync.PoolLogger           *msLog.LoggerglobalMiddles    []MiddlewareFuncerrorHandler     ErrorHandlerOpenGateWay      boolgatewayTreeNode  *gateway.TreeNodegatewayConfigMap map[string]gateway.GWConfignacosConfig      register.NacosConfigregisterClient   anyregister         string
}

func (e *Engine) SetNacosConfig(config register.NacosConfig) {e.nacosConfig = configclient, err := register.CreateNameClient(e.nacosConfig)if err != nil {panic(err)}e.registerClient = cliente.register = "nacos"
}
package mainimport ("github.com/mszlu521/msgo""github.com/mszlu521/msgo/gateway""github.com/mszlu521/msgo/register""net/http"
)func main() {engine := msgo.Default()engine.OpenGateWay = truevar configs []gateway.GWConfigconfigs = append(configs, gateway.GWConfig{Name: "order",Path: "/order/**",Host: "127.0.0.1",Port: 9003,Header: func(req *http.Request) {req.Header.Set("my", "mszlu")},}, gateway.GWConfig{Name:         "goodsCenter",Path:         "/goods/**",OpenRegister: true,Header: func(req *http.Request) {req.Header.Set("my", "mszlu")},})engine.SetNacosConfig(register.DefaultNacosConfig)engine.SetGateConfigs(configs)engine.Run(":80")
}

记得注册服务:

//注册服务client, _ := register.CreateNameClient(register.DefaultNacosConfig)config := register.NacosServiceConfig{Port: 9002, ServiceName: "goodsCenter", Ip: "127.0.0.1"}register.RegisterService(client, config)

acosConfig(register.DefaultNacosConfig)
engine.SetGateConfigs(configs)
engine.Run(“:80”)
}


记得注册服务:~~~go
//注册服务client, _ := register.CreateNameClient(register.DefaultNacosConfig)config := register.NacosServiceConfig{Port: 9002, ServiceName: "goodsCenter", Ip: "127.0.0.1"}register.RegisterService(client, config)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/513880.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

防患未然,OceanBase巡检工具应用实践——《OceanBase诊断系列》之五

1. OceanBase为什么要做巡检功能 尽管OceanBase拥有很好的MySQL兼容性,但在长期的生产环境中,部署不符合标准规范、硬件支持异常,或配置项错误等问题,这些短期不会出现的问题,仍会对数据库集群构成潜在的巨大风险。为…

使用API有效率地管理Dynadot域名,进行DNS域名解析

关于Dynadot Dynadot是通过ICANN认证的域名注册商,自2002年成立以来,服务于全球108个国家和地区的客户,为数以万计的客户提供简洁,优惠,安全的域名注册以及管理服务。 Dynadot平台操作教程索引(包括域名邮…

51camera简述面结构光成像

首先我们来看看结构光成像,它是使用特定的光图案和2D相机来捕获物体表面的三维轮廓的一种成像方法。其原理是将特定的窄带光投影到三维形状物体的表面上会产生一条照明线,该照明线从投影器的其他角度来看存在一定的变形,利用这种被三维形状调…

十四 超级数据查看器 讲解稿 背景和颜色

十四 超级数据查看器 讲解稿 背景和颜色 点击打开新页面播放视频教程 点击访问应用宝下载 讲解稿全文: 大家好,我们讲解一下 超级数据查看器 背景和颜色设置。 首先,我们打开超级数据查看器。 这节课设置的是 列表和详情界面的背景 和顶栏颜色。 …

网络编程作业day4

广播模型&#xff1a; 发送端&#xff1a; #include <myhead.h> int main(int argc, const char *argv[]) {//创建套接字int sfdsocket(AF_INET,SOCK_DGRAM,0);if(sfd-1){perror("socket error");return -1;}//设置套接字允许广播属性int broadcast1;if(sets…

Redis基本使用和基础知识整理

Redis是做什么的&#xff1f; Redis是一个开源&#xff0c;内存存储的数据结构服务器&#xff0c;可用作数据库&#xff0c;高速缓存和消息队列。Redis将数据储存在内存当中 内存的特点 易失性&#xff08;在断电之后数据就没有了&#xff09;进行读取数据等IO操作的速度要比…

ssm核心面试题汇总

文章目录 1. Spring1.1 Spring Beans1.谈谈你对Spring的理解以及优缺点2. 什么是Spring beans3. 配置注册Bean有哪几种方式4. Spring支持的几种bean的作用域5. 单例bean的优势6. 单例bean是线程安全的吗&#xff1f;如何优化为线程安全7. 谈一谈spring bean的自动装配8. Spring…

基于华为atlas的unet分割模型探索

Unet模型使用官方基于kaggle Carvana Image Masking Challenge数据集训练的模型。 模型输入为572*572*3&#xff0c;输出为572*572*2。分割目标分别为&#xff0c;0&#xff1a;背景&#xff0c;1&#xff1a;汽车。 Pytorch的pth模型转化onnx模型&#xff1a; import torchf…

Linux笔记--make

使用上一节的 main.c、add.c、sub.c文件进行编译&#xff0c;编译的过程有很多步骤&#xff0c;如果要重新编译&#xff0c;还需要再重来一遍&#xff0c;能不能一步完成这些步骤?将这些步骤写到makefile文件中&#xff0c;通过make工具进行编译 一个工程中的源文件不计其数&a…

Vue基础入门(4)- Vuex的使用

Vue基础入门&#xff08;4&#xff09;- Vuex的使用 Vuex 主要内容&#xff1a;Store以及其中的state、mutations、actions、getters、modules属性 介绍&#xff1a;Vuex 是一个 Vue 的 状态管理工具&#xff0c;状态就是数据。 大白话&#xff1a;Vuex 是一个插件&#xff…

Ubuntu18.04运行ORB-SLAM3

ORB-SLAM3复现(ubuntu18) 文章目录 ORB-SLAM3复现(ubuntu18)1 坐标系与外参Intrinsic parameters2 内参Intrinsic parameters2.1 相机内参① 针孔模型Pinhole② KannalaBrandt8模型③ Rectified相机 2.2 IMU内参 3 VI标定—外参3.1 Visual calibration3.2 Inertial calibration…

CSS标准文档流与脱离文档流,分享一点面试小经验

大厂面试真题整理 CSS&#xff1a; 1&#xff0c;盒模型 2&#xff0c;如何让一个盒子水平垂直居中&#xff1f; 3&#xff0c;css 优先级确定 4&#xff0c;解释下浮动和它的工作原理&#xff0c;清除浮动的方法&#xff1f; 5&#xff0c;CSS隐藏元素的几种方法 6&#xff0…