go语言学习 - caddy添加nacos-gateway

添加我们自己的module,找到这个文件 \caddy\modules\caddyhttp\standard\imports.go

package standard

import (
	// standard Caddy HTTP app modules
	_ "github.com/caddyserver/caddy/v2/modules/caddyhttp"
	_ "github.com/caddyserver/caddy/v2/modules/caddyhttp/caddyauth"
	//other...
	_ "github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy"
	//other..
	//添加我们的package
	_ "github.com/caddyserver/caddy/v2/modules/caddyhttp/nacosgateway"
)

 

先看看我们的配置,Caddyfile文件部分节点

:2015 {
	bind localhost 192.168.1.133
    root * D:\myenv\webvu
    file_server {
		index index.html index.htm
	}
		
	handle /gate/* {
		uri strip_prefix /gate		
        reverse_proxy {
			dynamic nacos {				
				server_addr 192.168.1.109
				server_port 8848
				name_space myenv
				gateway_addr 192.168.1.133
				gateway_port 2015
				gateway_service caddy
			}
		}
    }	
}

 在写下面代码前,我们还需要知道这个dynamic nacos的module.id是什么,可以断点这个文件caddyserver\caddy\modules.go

func GetModule(name string) (ModuleInfo, error) {
	modulesMu.RLock()
	defer modulesMu.RUnlock()
	m, ok := modules[name]
	if !ok {
		return ModuleInfo{}, fmt.Errorf("module not registered: %s", name)
	}
	return m, nil
}

  

 以下是部分关键代码。程序会在启动时向nacos注册caddy服务。/gate/{service}/htmlurl的请求来时,会向nacos获取{service}的实际地址,将/htmlurl转到该地址上。

package nacosgateway

import (
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"sync"

	"github.com/caddyserver/caddy/v2"
	"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
	"github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy"
	"github.com/nacos-group/nacos-sdk-go/v2/clients"
	"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client"
	"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
	"github.com/nacos-group/nacos-sdk-go/v2/model"
	"github.com/nacos-group/nacos-sdk-go/v2/vo"
)

func init() {
	caddy.RegisterModule(NacosUpstreamSource{})
}

// NacosUpstreamSource 实现了 UpstreamSource 接口
type NacosUpstreamSource struct {
	ServerAddr     string `json:"server_addr,omitempty"`
	ServerPort     uint64 `json:"server_port,omitempty"`	
	NameSpace      string `json:"namespace,omitempty"`
	GatewayAddr    string `json:"gateway_addr,omitempty"`
	GatewayPort    uint64 `json:"gateway_port,omitempty"`
	GatewayService string `json:"gateway_service,omitempty"`
	client         naming_client.INamingClient
	upstreamCache  map[string][]*reverseproxy.Upstream // 新增缓存字段
	cacheMutex     sync.RWMutex                        // 用于保护缓存的读写锁
}

// 初始化 NacosUpstreamSource 时初始化缓存
func NewNacosUpstreamSource() *NacosUpstreamSource {
	return &NacosUpstreamSource{
		// 其他字段初始化...
		upstreamCache: make(map[string][]*reverseproxy.Upstream),
	}
}

// Provision 初始化 Nacos 客户端
func (n *NacosUpstreamSource) Provision(ctx caddy.Context) error {
	serverConfigs := []constant.ServerConfig{
		{
			IpAddr: n.ServerAddr,
			Port:   n.ServerPort,
		},
	}
	clientConfig := constant.ClientConfig{
		NamespaceId:         n.NameSpace,
		TimeoutMs:           5000,
		NotLoadCacheAtStart: true,
		LogDir:              "/tmp/nacos/log",
		CacheDir:            "/tmp/nacos/cache",
	}
	var err error
	n.client, err = clients.NewNamingClient(
		vo.NacosClientParam{
			ClientConfig:  &clientConfig,
			ServerConfigs: serverConfigs,
		},
	)
	if err != nil {
		return err
	}
	// 注册服务实例
	success, err0 := n.client.RegisterInstance(vo.RegisterInstanceParam{
		Ip:          n.GatewayAddr,
		Port:        n.GatewayPort,
		ServiceName: n.GatewayService
	})
	if err0 != nil {
		panic(err0)
	}
	if !success {
		return fmt.Errorf("Service registration failed")
	}

	return nil
}

// GetUpstreams 从 Nacos 获取服务列表
func (n *NacosUpstreamSource) GetUpstreams(r *http.Request) ([]*reverseproxy.Upstream, error) {
	// 提取 URL 中的服务名
	serviceName, newPath := extractServiceName(r.URL.Path)
	// 从 URL 中去掉 /{service} 部分
	r.URL.Path = newPath
	if serviceName == "" {
		// 如果没有提取到,使用默认服务名
		return nil, fmt.Errorf("No service name found in URL")
	}
	// 先从缓存中查找
	n.cacheMutex.RLock()
	upstreams, exists := n.upstreamCache[serviceName]
	n.cacheMutex.RUnlock()
	if exists {
		return upstreams, nil
	}
	serviceInfo, err := n.client.GetService(vo.GetServiceParam{
		ServiceName: serviceName,
	})
	if err != nil {
		return nil, err
	}
	if len(serviceInfo.Hosts) == 0 {
		return nil, fmt.Errorf("No instances found for service %s", serviceName)
	}
	// 构建 Upstream
	upstreams = make([]*reverseproxy.Upstream, 0, len(serviceInfo.Hosts))
	for _, instance := range serviceInfo.Hosts {
		upstream := &reverseproxy.Upstream{
			Dial: fmt.Sprintf("%s:%d", instance.Ip, instance.Port),
		}
		upstreams = append(upstreams, upstream)
	}
	// 将结果存入缓存
	n.cacheMutex.Lock()
	n.upstreamCache[serviceName] = upstreams
	n.cacheMutex.Unlock()
	return upstreams, nil
}

// CaddyModule 返回模块信息
func (NacosUpstreamSource) CaddyModule() caddy.ModuleInfo {
	return caddy.ModuleInfo{
		ID:  "http.reverse_proxy.upstreams.nacos",
		New: func() caddy.Module { return NewNacosUpstreamSource() },
	}
}

func (n *NacosUpstreamSource) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
	d.Next() // 跳过指令名: nacos
	for d.NextBlock(0) {
		switch d.Val() {
		case "server_addr":
			if !d.NextArg() {
				return d.ArgErr()
			}
			n.ServerAddr = d.Val()
		//其他属性
		case "gateway_service":
			if !d.NextArg() {
				return d.ArgErr()
			}
			n.GatewayService = d.Val()
		default:
			return d.Errf("unrecognized subdirective %s", d.Val())
		}
	}
	return nil
}


var _ caddy.Provisioner = (*NacosUpstreamSource)(nil)
var _ reverseproxy.UpstreamSource = (*NacosUpstreamSource)(nil)

  

后面学习一下seaweedfs的源代码。

本文只发表在博客网,请勿转载!

posted @ 2025-03-13 13:06  生命体验之kevin-Y  阅读(11)  评论(0)    收藏  举报