Compare commits
5 Commits
2c81e99f4e
...
cd2530afa4
Author | SHA1 | Date | |
---|---|---|---|
cd2530afa4 | |||
5ebdb0b747 | |||
441132c04f | |||
200820df93 | |||
112a67a6cb |
18
.env
Normal file
18
.env
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Loki配置
|
||||||
|
LOKI_HOST=192.168.0.124
|
||||||
|
LOKI_PORT=3100
|
||||||
|
LOKI_SOURCE=goweb
|
||||||
|
# Nacos配置
|
||||||
|
NACOS_HOST=
|
||||||
|
NACOS_PORT=8848
|
||||||
|
# 命名空间,用默认的public的话这儿就不写
|
||||||
|
NACOS_NAMESPACE=
|
||||||
|
# 除本文件以外的其他托管到Nacos的配置文件,如果有多个则以半角分号`;`隔开 Ps. 后面可以把NACOS_*和系统启动相关的留着,其他的全部托管到Nacos
|
||||||
|
NACOS_CONFIG_NAME=gateway.yml
|
||||||
|
# 系统启动配置
|
||||||
|
# Jaeger链路追踪
|
||||||
|
JAEGER_SERVER=192.168.0.124:6831
|
||||||
|
# 系统名称,注册到Nacos需要,比如支付系统可以写mb-pay
|
||||||
|
APP_NAME=goweb
|
||||||
|
# 系统运行端口
|
||||||
|
PORT=8888
|
@ -12,7 +12,7 @@ WORKDIR /builder
|
|||||||
COPY . .
|
COPY . .
|
||||||
RUN go mod download && go build -o app
|
RUN go mod download && go build -o app
|
||||||
RUN ls -lh && chmod +x ./app
|
RUN ls -lh && chmod +x ./app
|
||||||
FROM golang:alpine as runner
|
FROM alpine as runner
|
||||||
MAINTAINER LiXunHuan(lxh@cxh.cn)
|
MAINTAINER LiXunHuan(lxh@cxh.cn)
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ENV TZ=Asia/Shanghai
|
ENV TZ=Asia/Shanghai
|
||||||
|
17
config/app_info.go
Normal file
17
config/app_info.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import "gateway/utils"
|
||||||
|
|
||||||
|
type appInfo struct {
|
||||||
|
AppName string
|
||||||
|
Port uint64
|
||||||
|
JaegerServer string
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitAppInfo() {
|
||||||
|
appName := utils.GetEnvVal("APP_NAME", "go-web")
|
||||||
|
port := utils.GetEnvIntVal("PORT", 8888)
|
||||||
|
jaegerServer := utils.GetEnvVal("JAEGER_SERVER", "")
|
||||||
|
|
||||||
|
AppInfo = appInfo{appName, uint64(port), jaegerServer}
|
||||||
|
}
|
7
config/config.go
Normal file
7
config/config.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
var (
|
||||||
|
AppInfo appInfo
|
||||||
|
LokiConfig lokiConfig
|
||||||
|
NacosConfig nacosConfig
|
||||||
|
)
|
27
config/loki.go
Normal file
27
config/loki.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"gateway/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Loki配置信息
|
||||||
|
type lokiConfig struct {
|
||||||
|
Host string
|
||||||
|
Port string
|
||||||
|
Source string
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitLokiConfig 初始化Loki配置
|
||||||
|
func InitLokiConfig() {
|
||||||
|
host := utils.GetEnvVal("LOKI_HOST", "")
|
||||||
|
port := utils.GetEnvVal("LOKI_PORT", "")
|
||||||
|
source := utils.GetEnvVal("LOKI_SOURCE", "goweb")
|
||||||
|
|
||||||
|
LokiConfig = lokiConfig{Host: host, Port: port, Source: source}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPushURL 获取组装后的日志推送接口
|
||||||
|
func (c lokiConfig) GetPushURL() string {
|
||||||
|
return fmt.Sprintf("http://%v:%v/loki/api/v1/push", c.Host, c.Port)
|
||||||
|
}
|
28
config/nacos.go
Normal file
28
config/nacos.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gateway/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Nacos配置
|
||||||
|
type nacosConfig struct {
|
||||||
|
Host string // 主机
|
||||||
|
Port uint64 // 端口
|
||||||
|
NamespaceId string // 命名空间
|
||||||
|
CenterConfigName string // 外部配置文件名,多个以逗号隔开
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitNacosConfig 初始化OSS配置
|
||||||
|
func InitNacosConfig() {
|
||||||
|
host := utils.GetEnvVal("NACOS_HOST", "nacos-headless")
|
||||||
|
port := utils.GetEnvIntVal("NACOS_PORT", 8848)
|
||||||
|
namespaceId := utils.GetEnvVal("NACOS_NAMESPACE", "")
|
||||||
|
centerConfigName := utils.GetEnvVal("NACOS_CONFIG_NAME", "application.yml")
|
||||||
|
|
||||||
|
NacosConfig = nacosConfig{
|
||||||
|
Host: host,
|
||||||
|
Port: uint64(port),
|
||||||
|
NamespaceId: namespaceId,
|
||||||
|
CenterConfigName: centerConfigName,
|
||||||
|
}
|
||||||
|
}
|
33
core/config.go
Normal file
33
core/config.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Gateway struct {
|
||||||
|
Routes []struct {
|
||||||
|
Path string `yaml:"path"`
|
||||||
|
Service string `yaml:"service"`
|
||||||
|
Enable bool `yaml:"enable"`
|
||||||
|
} `yaml:"routes"`
|
||||||
|
} `yaml:"gateway"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConfigChanged(data string) {
|
||||||
|
// 从配置文件解析为对象
|
||||||
|
config := Config{}
|
||||||
|
err := yaml.Unmarshal([]byte(data), &config)
|
||||||
|
if err != nil {
|
||||||
|
Log.Error("解析配置文本失败: %v\n", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rs := config.Gateway.Routes
|
||||||
|
var sma []serviceMap
|
||||||
|
for _, r := range rs {
|
||||||
|
item := NewServiceMapItem(r.Path, r.Service, r.Enable)
|
||||||
|
sma = append(sma, item)
|
||||||
|
}
|
||||||
|
ServiceMap = sma
|
||||||
|
Log.Info("配置文件解析完毕")
|
||||||
|
}
|
7
core/core.go
Normal file
7
core/core.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
var (
|
||||||
|
NacosClient nacosClient
|
||||||
|
ServiceMap []serviceMap
|
||||||
|
Log Logger
|
||||||
|
)
|
74
core/logger.go
Normal file
74
core/logger.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"go.uber.org/zap/zapcore"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Logger struct {
|
||||||
|
zap *zap.SugaredLogger
|
||||||
|
loki lokiClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化Zap日志工具
|
||||||
|
func initZapLogger() *zap.SugaredLogger {
|
||||||
|
// 配置 sugaredLogger
|
||||||
|
writer := zapcore.AddSync(os.Stdout)
|
||||||
|
|
||||||
|
// 自定义时间输出格式
|
||||||
|
customTimeEncoder := func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
|
||||||
|
enc.AppendString("[" + t.Format("2006-01-02 15:04:05.000") + "]")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式相关的配置
|
||||||
|
encoderConfig := zap.NewProductionEncoderConfig()
|
||||||
|
// 修改时间戳的格式
|
||||||
|
encoderConfig.EncodeTime = customTimeEncoder
|
||||||
|
// 日志级别使用大写带颜色显示
|
||||||
|
encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
|
||||||
|
encoder := zapcore.NewConsoleEncoder(encoderConfig)
|
||||||
|
// 将日志级别设置为 DEBUG
|
||||||
|
core := zapcore.NewCore(encoder, writer, zapcore.DebugLevel)
|
||||||
|
// 增加 caller 信息
|
||||||
|
logger := zap.New(core, zap.AddCaller())
|
||||||
|
return logger.Sugar()
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitLogger 初始化日志系统
|
||||||
|
func InitLogger() {
|
||||||
|
zapLogger := initZapLogger()
|
||||||
|
loki := initLokiClient()
|
||||||
|
Log = Logger{zap: zapLogger, loki: loki}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug Debug级别日志
|
||||||
|
func (l Logger) Debug(template string, args ...interface{}) {
|
||||||
|
l.zap.Debugf(template, args...)
|
||||||
|
l.loki.Debug("", template, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info Info级别日志
|
||||||
|
func (l Logger) Info(template string, args ...interface{}) {
|
||||||
|
l.zap.Infof(template, args...)
|
||||||
|
l.loki.Info("", template, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn Warn级别日志
|
||||||
|
func (l Logger) Warn(template string, args ...interface{}) {
|
||||||
|
l.zap.Warnf(template, args...)
|
||||||
|
l.loki.Warn("", template, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error Error级别日志
|
||||||
|
func (l Logger) Error(template string, args ...interface{}) {
|
||||||
|
l.zap.Errorf(template, args...)
|
||||||
|
l.loki.Error("", template, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panic 打印异常并退出系统
|
||||||
|
func (l Logger) Panic(template string, args ...interface{}) {
|
||||||
|
l.loki.Error("", template, args...)
|
||||||
|
l.zap.Panicf(template, args...)
|
||||||
|
}
|
81
core/loki.go
Normal file
81
core/loki.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"gateway/config"
|
||||||
|
"github.com/AllCute/loki-client-go/loki"
|
||||||
|
"github.com/go-kit/kit/log"
|
||||||
|
"github.com/prometheus/common/model"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type lokiClient struct {
|
||||||
|
client *loki.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化Loki
|
||||||
|
func initLokiClient() lokiClient {
|
||||||
|
config.InitLokiConfig()
|
||||||
|
// 初始化配置
|
||||||
|
cfg, err := loki.NewDefaultConfig(config.LokiConfig.GetPushURL())
|
||||||
|
// 创建连接对象
|
||||||
|
client, err := loki.NewWithLogger(cfg, log.NewNopLogger())
|
||||||
|
if err != nil {
|
||||||
|
Log.zap.Panicf("Loki初始化失败: %v", err.Error())
|
||||||
|
}
|
||||||
|
label := model.LabelSet{"job": "initialization"}
|
||||||
|
label["source"] = model.LabelValue(config.LokiConfig.Source)
|
||||||
|
label["level"] = "Debug"
|
||||||
|
err = client.Handle(label, time.Now().Local(), "Loki服务连接成功")
|
||||||
|
if err != nil {
|
||||||
|
Log.zap.Errorf("日志推送到Loki失败: %v", err.Error())
|
||||||
|
}
|
||||||
|
return lokiClient{client: client}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送日志到Loki
|
||||||
|
func (c lokiClient) send(level string, job string, logStr string) {
|
||||||
|
label := model.LabelSet{"job": model.LabelValue(job)}
|
||||||
|
label["source"] = model.LabelValue(config.LokiConfig.Source)
|
||||||
|
label["level"] = model.LabelValue(level)
|
||||||
|
err := c.client.Handle(label, time.Now().Local(), logStr)
|
||||||
|
if err != nil {
|
||||||
|
Log.zap.Errorf("日志推送到Loki失败: %v", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug Debug日志
|
||||||
|
func (c lokiClient) Debug(job, template string, args ...interface{}) {
|
||||||
|
logStr := template
|
||||||
|
if len(args) > 0 {
|
||||||
|
logStr = fmt.Sprintf(template, args...)
|
||||||
|
}
|
||||||
|
c.send("Debug", job, logStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info Info日志
|
||||||
|
func (c lokiClient) Info(job, template string, args ...interface{}) {
|
||||||
|
logStr := template
|
||||||
|
if len(args) > 0 {
|
||||||
|
logStr = fmt.Sprintf(template, args...)
|
||||||
|
}
|
||||||
|
c.send("Info", job, logStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn Warn日志
|
||||||
|
func (c lokiClient) Warn(job, template string, args ...interface{}) {
|
||||||
|
logStr := template
|
||||||
|
if len(args) > 0 {
|
||||||
|
logStr = fmt.Sprintf(template, args...)
|
||||||
|
}
|
||||||
|
c.send("Warn", job, logStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error Error日志
|
||||||
|
func (c lokiClient) Error(job, template string, args ...interface{}) {
|
||||||
|
logStr := template
|
||||||
|
if len(args) > 0 {
|
||||||
|
logStr = fmt.Sprintf(template, args...)
|
||||||
|
}
|
||||||
|
c.send("Error", job, logStr)
|
||||||
|
}
|
81
core/nacos.go
Normal file
81
core/nacos.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/nacos-group/nacos-sdk-go/clients/config_client"
|
||||||
|
"github.com/nacos-group/nacos-sdk-go/clients/naming_client"
|
||||||
|
"github.com/nacos-group/nacos-sdk-go/vo"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type nacosClient struct {
|
||||||
|
client naming_client.INamingClient
|
||||||
|
config config_client.IConfigClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNacosClient(c naming_client.INamingClient, n config_client.IConfigClient) nacosClient {
|
||||||
|
return nacosClient{c, n}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remote 发起远程调用
|
||||||
|
func (n nacosClient) Remote(ctx *gin.Context) {
|
||||||
|
// 取出URI
|
||||||
|
uri := ctx.Request.RequestURI
|
||||||
|
// 截取第二个/前面那一段
|
||||||
|
pathAry := strings.Split(uri, "/")
|
||||||
|
var service serviceMap
|
||||||
|
apiService := fmt.Sprintf("/%v", pathAry[1])
|
||||||
|
for _, s := range ServiceMap {
|
||||||
|
if s.Path != "" && s.Path == apiService {
|
||||||
|
service = s
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if service.Service == "" {
|
||||||
|
ctx.String(http.StatusNotFound, "服务不可达")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !service.Enable {
|
||||||
|
ctx.String(http.StatusServiceUnavailable, "系统维护中")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
instance, err := n.client.SelectOneHealthyInstance(vo.SelectOneHealthInstanceParam{
|
||||||
|
ServiceName: service.Service,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
Log.Error("获取健康服务失败: %v\n", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 组装内部接口
|
||||||
|
apiUrl := fmt.Sprintf("http://%v:%v%v", instance.Ip, instance.Port, uri)
|
||||||
|
// 创建Request对象
|
||||||
|
req, err := http.NewRequest(ctx.Request.Method, apiUrl, ctx.Request.Body)
|
||||||
|
if err != nil {
|
||||||
|
Log.Error("请求异常: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 填充Form参数(大概率用不上)
|
||||||
|
req.Form = ctx.Request.Form
|
||||||
|
// 填充链路追踪标记
|
||||||
|
req.Header.Add("uber-trace-id", ctx.GetString("UberTraceId"))
|
||||||
|
// 请求ID
|
||||||
|
req.Header.Add("X-Request-Id", ctx.GetString("X-Request-Id"))
|
||||||
|
// 设置来源
|
||||||
|
req.Header.Add("From", "internal")
|
||||||
|
// 发起请求
|
||||||
|
client := &http.Client{}
|
||||||
|
response, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
Log.Error("请求异常: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 返回结果到前端
|
||||||
|
sss, _ := ioutil.ReadAll(response.Body)
|
||||||
|
Log.Debug(string(sss))
|
||||||
|
ctx.String(response.StatusCode, string(sss))
|
||||||
|
}
|
16
core/service.go
Normal file
16
core/service.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
type serviceMap struct {
|
||||||
|
Path string
|
||||||
|
Service string
|
||||||
|
Enable bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServiceMapItem(k, v string, e bool) serviceMap {
|
||||||
|
//var sma []serviceMap
|
||||||
|
// 从Nacos读取规则
|
||||||
|
// gateway:
|
||||||
|
// - path: /user
|
||||||
|
// service: mb-user-service
|
||||||
|
return serviceMap{k, v, e}
|
||||||
|
}
|
103
feign.go
103
feign.go
@ -1,103 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/nacos-group/nacos-sdk-go/clients"
|
|
||||||
"github.com/nacos-group/nacos-sdk-go/clients/naming_client"
|
|
||||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
|
||||||
"github.com/nacos-group/nacos-sdk-go/vo"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
var nameClient naming_client.INamingClient
|
|
||||||
|
|
||||||
func initNacos() {
|
|
||||||
sc := []constant.ServerConfig{
|
|
||||||
*constant.NewServerConfig("nacos", 8848),
|
|
||||||
}
|
|
||||||
cc := constant.ClientConfig{
|
|
||||||
AppName: "gateway",
|
|
||||||
//NamespaceId: "e56f939e-6d22-449c-97d2-39a8ae5afd58", //namespace id
|
|
||||||
NamespaceId: "",
|
|
||||||
TimeoutMs: 5000,
|
|
||||||
NotLoadCacheAtStart: true,
|
|
||||||
RotateTime: "1h",
|
|
||||||
MaxAge: 3,
|
|
||||||
LogLevel: "debug",
|
|
||||||
}
|
|
||||||
client, err := clients.NewNamingClient(
|
|
||||||
vo.NacosClientParam{
|
|
||||||
ClientConfig: &cc,
|
|
||||||
ServerConfigs: sc,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
ip := "gateway-demo"
|
|
||||||
if ips := getIps(); ips != nil {
|
|
||||||
ip = ips[0]
|
|
||||||
}
|
|
||||||
success, _ := client.RegisterInstance(vo.RegisterInstanceParam{
|
|
||||||
Ip: ip,
|
|
||||||
Port: 8889,
|
|
||||||
Weight: 10,
|
|
||||||
Enable: true,
|
|
||||||
Healthy: true,
|
|
||||||
ServiceName: "gateway",
|
|
||||||
Ephemeral: true,
|
|
||||||
})
|
|
||||||
log.Println("Nacos注册结果: ", success)
|
|
||||||
if !success {
|
|
||||||
log.Fatal("服务注册失败,退出程序")
|
|
||||||
}
|
|
||||||
nameClient = client
|
|
||||||
}
|
|
||||||
|
|
||||||
func get(method, url string) string {
|
|
||||||
info, err := nameClient.SelectAllInstances(vo.SelectAllInstancesParam{
|
|
||||||
ServiceName: "api1",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return "获取服务异常:" + err.Error()
|
|
||||||
}
|
|
||||||
log.Println("获取到实例数量:", len(info))
|
|
||||||
instance, err := nameClient.SelectOneHealthyInstance(vo.SelectOneHealthInstanceParam{
|
|
||||||
ServiceName: "api1",
|
|
||||||
//GroupName: "Micro", // 默认值DEFAULT_GROUP
|
|
||||||
//Clusters: []string{pojo.InitConf.CurVersion}, // 默认值DEFAULT
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return "获取服务异常:" + err.Error()
|
|
||||||
}
|
|
||||||
apiUrl := fmt.Sprintf("http://%v:%v%v", instance.Ip, instance.Port, url)
|
|
||||||
response, err := http.Get(apiUrl)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("请求异常: %v", err)
|
|
||||||
}
|
|
||||||
content, err := ioutil.ReadAll(response.Body)
|
|
||||||
respBody := string(content)
|
|
||||||
return respBody
|
|
||||||
}
|
|
||||||
|
|
||||||
func post(url string) string {
|
|
||||||
instance, err := nameClient.SelectOneHealthyInstance(vo.SelectOneHealthInstanceParam{
|
|
||||||
ServiceName: "api1",
|
|
||||||
//GroupName: "Micro", // 默认值DEFAULT_GROUP
|
|
||||||
//Clusters: []string{pojo.InitConf.CurVersion}, // 默认值DEFAULT
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return "获取服务异常:" + err.Error()
|
|
||||||
}
|
|
||||||
apiUrl := fmt.Sprintf("http://%v:%v%v", instance.Ip, instance.Port, url)
|
|
||||||
response, err := http.Post(apiUrl, "application/json", nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("请求异常: %v", err)
|
|
||||||
}
|
|
||||||
content, err := ioutil.ReadAll(response.Body)
|
|
||||||
respBody := string(content)
|
|
||||||
return respBody
|
|
||||||
}
|
|
37
go.mod
37
go.mod
@ -1,37 +1,20 @@
|
|||||||
module gateway
|
module gateway
|
||||||
|
|
||||||
go 1.17
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gin-gonic/gin v1.7.4
|
github.com/gin-gonic/gin v1.7.4
|
||||||
|
github.com/go-kit/kit v0.11.0
|
||||||
github.com/nacos-group/nacos-sdk-go v1.0.8
|
github.com/nacos-group/nacos-sdk-go v1.0.8
|
||||||
|
github.com/opentracing/opentracing-go v1.2.0
|
||||||
|
github.com/prometheus/common v0.30.0
|
||||||
|
github.com/uber/jaeger-client-go v2.29.1+incompatible
|
||||||
|
go.uber.org/zap v1.17.0
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.18 // indirect
|
github.com/AllCute/loki-client-go v1.0.0
|
||||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 // indirect
|
github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
|
||||||
github.com/go-errors/errors v1.0.1 // indirect
|
|
||||||
github.com/go-playground/locales v0.13.0 // indirect
|
|
||||||
github.com/go-playground/universal-translator v0.17.0 // indirect
|
|
||||||
github.com/go-playground/validator/v10 v10.4.1 // indirect
|
|
||||||
github.com/golang/protobuf v1.3.3 // indirect
|
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
|
|
||||||
github.com/json-iterator/go v1.1.9 // indirect
|
|
||||||
github.com/leodido/go-urn v1.2.0 // indirect
|
|
||||||
github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f // indirect
|
|
||||||
github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect
|
|
||||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
|
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
|
||||||
github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3 // indirect
|
|
||||||
github.com/ugorji/go/codec v1.1.7 // indirect
|
|
||||||
go.uber.org/atomic v1.6.0 // indirect
|
|
||||||
go.uber.org/multierr v1.5.0 // indirect
|
|
||||||
go.uber.org/zap v1.15.0 // indirect
|
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
|
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 // indirect
|
|
||||||
gopkg.in/ini.v1 v1.42.0 // indirect
|
|
||||||
gopkg.in/yaml.v2 v2.2.8 // indirect
|
|
||||||
)
|
)
|
||||||
|
16
initialization/init.go
Normal file
16
initialization/init.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package initialization
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gateway/config"
|
||||||
|
"gateway/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InitSystem 初始化系统
|
||||||
|
func InitSystem() {
|
||||||
|
// 初始化APP信息
|
||||||
|
config.InitAppInfo()
|
||||||
|
// 初始化日志工具
|
||||||
|
core.InitLogger()
|
||||||
|
// Nacos
|
||||||
|
initNacos()
|
||||||
|
}
|
92
initialization/nacos.go
Normal file
92
initialization/nacos.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package initialization
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gateway/config"
|
||||||
|
"gateway/core"
|
||||||
|
"gateway/utils"
|
||||||
|
"github.com/nacos-group/nacos-sdk-go/clients"
|
||||||
|
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||||
|
"github.com/nacos-group/nacos-sdk-go/vo"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 初始化Nacos注册
|
||||||
|
func initNacos() {
|
||||||
|
config.InitNacosConfig()
|
||||||
|
|
||||||
|
sc := []constant.ServerConfig{
|
||||||
|
*constant.NewServerConfig(config.NacosConfig.Host, config.NacosConfig.Port),
|
||||||
|
}
|
||||||
|
cc := constant.ClientConfig{
|
||||||
|
AppName: config.AppInfo.AppName,
|
||||||
|
NamespaceId: config.NacosConfig.NamespaceId,
|
||||||
|
TimeoutMs: 5000,
|
||||||
|
NotLoadCacheAtStart: true,
|
||||||
|
RotateTime: "1h",
|
||||||
|
MaxAge: 3,
|
||||||
|
LogLevel: "debug",
|
||||||
|
}
|
||||||
|
configParam := vo.NacosClientParam{
|
||||||
|
ClientConfig: &cc,
|
||||||
|
ServerConfigs: sc,
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := clients.NewNamingClient(configParam)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
ip := "gateway"
|
||||||
|
if ips := utils.GetIps(); ips != nil {
|
||||||
|
ip = ips[0]
|
||||||
|
}
|
||||||
|
success, _ := client.RegisterInstance(vo.RegisterInstanceParam{
|
||||||
|
Ip: ip,
|
||||||
|
Port: config.AppInfo.Port,
|
||||||
|
Weight: 10,
|
||||||
|
Enable: true,
|
||||||
|
Healthy: true,
|
||||||
|
ServiceName: "gateway",
|
||||||
|
Ephemeral: true,
|
||||||
|
})
|
||||||
|
core.Log.Debug("Nacos注册结果: %v", success)
|
||||||
|
if !success {
|
||||||
|
core.Log.Panic("服务注册失败,退出程序")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印所有服务
|
||||||
|
go func() {
|
||||||
|
instances, err := client.SelectAllInstances(vo.SelectAllInstancesParam{
|
||||||
|
ServiceName: config.AppInfo.AppName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
core.Log.Error("获取所有服务失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
core.Log.Debug("获取到服务总数: %v", len(instances))
|
||||||
|
for _, instance := range instances {
|
||||||
|
core.Log.Debug("服务ID: %v --> %v:%v", instance.InstanceId, instance.Ip, instance.Port)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
configClient, err := clients.NewConfigClient(configParam)
|
||||||
|
if err != nil {
|
||||||
|
core.Log.Error("创建配置连接失败: %v", err.Error())
|
||||||
|
}
|
||||||
|
_ = configClient.ListenConfig(vo.ConfigParam{
|
||||||
|
DataId: config.NacosConfig.CenterConfigName,
|
||||||
|
Group: "DEFAULT_GROUP",
|
||||||
|
OnChange: configChanged,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 读取初始配置
|
||||||
|
core.NacosClient = core.NewNacosClient(client, configClient)
|
||||||
|
configStr, err := configClient.GetConfig(vo.ConfigParam{DataId: "gateway.yml", Group: "DEFAULT_GROUP"})
|
||||||
|
if err != nil {
|
||||||
|
core.Log.Panic("读取配置文件错误: %v", err.Error())
|
||||||
|
}
|
||||||
|
core.ConfigChanged(configStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func configChanged(namespace, group, dataId, data string) {
|
||||||
|
core.ConfigChanged(data)
|
||||||
|
}
|
60
main.go
60
main.go
@ -1,47 +1,39 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"gateway/core"
|
||||||
|
"gateway/initialization"
|
||||||
|
"gateway/middleware"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func getIps() []string {
|
|
||||||
addrs, err := net.InterfaceAddrs()
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var ips []string
|
|
||||||
for _, address := range addrs {
|
|
||||||
// 检查ip地址判断是否回环地址
|
|
||||||
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
|
||||||
if ipnet.IP.To4() != nil {
|
|
||||||
ip := ipnet.IP.String()
|
|
||||||
fmt.Println(ip)
|
|
||||||
ips = append(ips, ip)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//ipStr := strings.Join(aaaa, ",")
|
|
||||||
return ips
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
// 初始化系统
|
||||||
|
initialization.InitSystem()
|
||||||
|
// 创建默认Web服务
|
||||||
app := gin.Default()
|
app := gin.Default()
|
||||||
initNacos()
|
|
||||||
|
|
||||||
app.GET("/hello", func(context *gin.Context) {
|
app.Use(middleware.GenRequestId(), middleware.OpenTracing())
|
||||||
context.String(http.StatusOK, get("get", context.Request.RequestURI))
|
|
||||||
})
|
|
||||||
|
|
||||||
app.POST("/hello", func(context *gin.Context) {
|
app.Any("/*action", core.NacosClient.Remote)
|
||||||
context.String(http.StatusOK, post(context.Request.RequestURI))
|
|
||||||
})
|
|
||||||
|
|
||||||
app.GET("/ip", func(context *gin.Context) {
|
//app.GET("/hello", func(context *gin.Context) {
|
||||||
context.String(http.StatusOK, get("get", context.Request.RequestURI))
|
// dd := context.GetString("UberTraceId")
|
||||||
})
|
// //log.Println("数据是否存在: ", boo)
|
||||||
|
// //if boo {
|
||||||
|
// // log.Println(dd)
|
||||||
|
// //}
|
||||||
|
// context.String(http.StatusOK, get("get", context.Request.RequestURI, context.GetString("X-Request-Id"), dd))
|
||||||
|
//})
|
||||||
|
//
|
||||||
|
//app.POST("/hello", func(context *gin.Context) {
|
||||||
|
// context.String(http.StatusOK, post(context.Request.RequestURI))
|
||||||
|
//})
|
||||||
|
//
|
||||||
|
//app.GET("/ip", func(context *gin.Context) {
|
||||||
|
// dd := context.GetString("UberTraceId")
|
||||||
|
// context.String(http.StatusOK, get("get", context.Request.RequestURI, context.GetString("X-Request-Id"), dd))
|
||||||
|
//})
|
||||||
|
|
||||||
app.Run(":8889")
|
_ = app.Run(":8889")
|
||||||
}
|
}
|
||||||
|
74
middleware/jaeger.go
Normal file
74
middleware/jaeger.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
gc "gateway/config"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/opentracing/opentracing-go"
|
||||||
|
"github.com/opentracing/opentracing-go/ext"
|
||||||
|
"github.com/uber/jaeger-client-go/config"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
func OpenTracing() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
var parentSpan opentracing.Span
|
||||||
|
|
||||||
|
tracer, closer := NewJaegerTracer()
|
||||||
|
defer closer.Close()
|
||||||
|
|
||||||
|
spCtx, err := opentracing.GlobalTracer().Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(c.Request.Header))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
parentSpan = tracer.StartSpan(c.Request.URL.Path)
|
||||||
|
defer parentSpan.Finish()
|
||||||
|
} else {
|
||||||
|
parentSpan = opentracing.StartSpan(
|
||||||
|
c.Request.URL.Path,
|
||||||
|
opentracing.ChildOf(spCtx),
|
||||||
|
opentracing.Tag{Key: string(ext.Component), Value: "HTTP"},
|
||||||
|
ext.SpanKindRPCServer,
|
||||||
|
)
|
||||||
|
defer parentSpan.Finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Set("Tracer", tracer)
|
||||||
|
asd := fmt.Sprintf("%v", parentSpan.Context())
|
||||||
|
c.Set("UberTraceId", asd)
|
||||||
|
c.Set("ParentSpanContext", parentSpan.Context())
|
||||||
|
|
||||||
|
c.Next()
|
||||||
|
|
||||||
|
ext.HTTPStatusCode.Set(parentSpan, uint16(c.Writer.Status()))
|
||||||
|
|
||||||
|
if c.Writer.Status() > 299 {
|
||||||
|
ext.Error.Set(parentSpan, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//var Tracer opentracing.Tracer
|
||||||
|
|
||||||
|
func NewJaegerTracer() (opentracing.Tracer, io.Closer) {
|
||||||
|
cfg := &config.Configuration{
|
||||||
|
Sampler: &config.SamplerConfig{
|
||||||
|
Type: "const", //固定采样
|
||||||
|
Param: 1, //1=全采样、0=不采样
|
||||||
|
},
|
||||||
|
|
||||||
|
Reporter: &config.ReporterConfig{
|
||||||
|
LogSpans: true,
|
||||||
|
LocalAgentHostPort: gc.AppInfo.JaegerServer,
|
||||||
|
},
|
||||||
|
|
||||||
|
ServiceName: gc.AppInfo.AppName,
|
||||||
|
}
|
||||||
|
|
||||||
|
tracer, closer, err := cfg.NewTracer()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
opentracing.SetGlobalTracer(tracer)
|
||||||
|
//Tracer = tracer
|
||||||
|
return tracer, closer
|
||||||
|
}
|
24
middleware/request.go
Normal file
24
middleware/request.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gateway/core"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/nacos-group/nacos-sdk-go/inner/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GenRequestId 生成RequestId
|
||||||
|
func GenRequestId() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
requestId := c.Request.Header.Get("X-Request-Id")
|
||||||
|
if requestId == "" {
|
||||||
|
u, err := uuid.NewV4()
|
||||||
|
if err != nil {
|
||||||
|
core.Log.Error("生成UUID错误: %v\n", err.Error())
|
||||||
|
} else {
|
||||||
|
requestId = u.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.Set("X-Request-Id", requestId)
|
||||||
|
c.Writer.Header().Set("X-Request-Id", requestId)
|
||||||
|
}
|
||||||
|
}
|
41
utils/env_utils.go
Normal file
41
utils/env_utils.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 从环境变量获取字符串类型值
|
||||||
|
func GetEnvVal(key, defaultVal string) string {
|
||||||
|
val, exist := os.LookupEnv(key)
|
||||||
|
if !exist {
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从环境变量获取数字类型值
|
||||||
|
func GetEnvIntVal(key string, defaultVal int) int {
|
||||||
|
valStr, exist := os.LookupEnv(key)
|
||||||
|
if !exist {
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
val, err := strconv.Atoi(valStr)
|
||||||
|
if err != nil {
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从环境变量获取数字类型值
|
||||||
|
func GetEnvBoolVal(key string, defaultVal bool) bool {
|
||||||
|
valStr, exist := os.LookupEnv(key)
|
||||||
|
if !exist {
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
val, err := strconv.ParseBool(valStr)
|
||||||
|
if err != nil {
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
27
utils/ip_utils.go
Normal file
27
utils/ip_utils.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetIps 获取本机IP地址
|
||||||
|
func GetIps() []string {
|
||||||
|
addrs, err := net.InterfaceAddrs()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var ips []string
|
||||||
|
for _, address := range addrs {
|
||||||
|
// 检查ip地址判断是否回环地址
|
||||||
|
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
||||||
|
if ipnet.IP.To4() != nil {
|
||||||
|
ip := ipnet.IP.String()
|
||||||
|
fmt.Println(ip)
|
||||||
|
ips = append(ips, ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//ipStr := strings.Join(aaaa, ",")
|
||||||
|
return ips
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user