需求
每隔几秒主动调用api拉取信息,会对服务器造成很大的压力,特别对于小型应用,只有一台服务器,配置也不高。客户端要实时的接收一些消息,消息推送也提升了用户的体验。很有必要。
思路
- 使用RabbitMQ接收消息,再推送给客户端
- 使用gin http api接收消息,再推送给客户端
- 客户端通过websocket连接到推送服务,然后等待接收消息并处理消息
- 使用jwt-token验证客户端真实性,确定用户身份
实现
设置模块
读取进行目录的config.toml文件,做为配置文件。
-
rabbit_conn_str RabbitMQ消息队列配置串,root是用户名,123是密码,@后为主机端口,/test是租户
-
jwt_secret jwt使用的加密串,与主服务保证一致
-
public_key_path private_key_path https配置,公钥与私钥,不配置不开启https
-
http_port http服务端口号
-
white_ips gin http 服务的白名单,使用白名单简单验证接口调用者的身份
rabbit_conn_str = "amqp://root:123@localhost:5672/test" #2323
jwt_secret = '123123123123123123123'
public_key_path = "./server.crt"
private_key_path = "./server.key"
http_port = "80"
white_ips = "127.0.0.1"
package main
import (
"fmt"
"github.com/BurntSushi/toml"
"os"
)
var CONFIG = GetConfig("config.toml")
// Config
// 系统配置类
type Config struct {
RabbitConnStr string `json:"rabbit_conn_str" toml:"rabbit_conn_str"`
JwtSecret string `json:"jwt_secret" toml:"jwt_secret"`
PublicKeyPath string `json:"public_key_path" toml:"public_key_path"`
PrivateKeyPath string `json:"private_key_path" toml:"private_key_path"`
HttpPort string `json:"http_port" toml:"http_port"`
WhiteIps string `json:"white_ips" toml:"white_ips"`
}
// GetConfig
// 获取配置
func GetConfig(path string) Config {
content, err := os.ReadFile(path)
if err != nil {
panic(err)
}
config := Config{}
mData, err := toml.Decode(string(content), &config)
if err != nil {
panic(err)
}
fmt.Printf("%s", mData)
return config
}
日志模块
日志使用滴滴的zap
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
使用"gopkg.in/natefinch/lumberjack.v2"做日志轮换
MaxSize 每个日志文件的最大大小,单位MB
MaxBackups 最多保留多少文件
MaxAge 最多保留几天
Compress 是否压缩日志文件
Filename 日志文件名,加上日志,加上主机名
File = &lumberjack.Logger{
Filename: "./logs/" + time.Now().Format("20060102150405") + hostname + ".log", // ⽇志⽂件路径
MaxSize: 500, // 文件最大大小 500MB
MaxBackups: 3, // 最多保留3个备份
MaxAge: 7, // 最多保留多少天
Compress: true, // 是否压缩 默认不压缩
}
FileW := zapcore.AddSync(File)
encoderCfg := zapcore.EncoderConfig{
MessageKey: "msg", // msg key 日志主体内容字段名msg
LevelKey: "level", // 日志级别字段名level
NameKey: "logger", // 日志名
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.StringDurationEncoder,
}
core := zapcore.NewCore(zapcore.NewJSONEncoder(encoderCfg), FileW, zap.DebugLevel)
LOG = zap.New(core).WithOptions() // options...
关闭日志时先写入磁盘再关闭日志再关闭日志文件
err := LOG.Sync() // 同步文件到磁盘
if err != nil {
fmt.Printf("log sync err %v\n", err)
}
if File != nil {
err = File.Close() // 关闭日志文件
if err != nil {
fmt.Printf("sync err %s", err.Error())
}
}
jwt 模块
直接上代码。 主要功能: 生成token 与验证token
package main
import (
"errors"
"github.com/dgrijalva/jwt-go"
"time"
)
//GetNewJwtToken 創建一個新的jwt,
func GetNewJwtToken(hs256Key []byte, userClaims *UserClaims) (string, error) {
jwtToken := jwt.New(jwt.SigningMethodHS256)
jwtToken.Claims = userClaims
return jwtToken.SignedString(hs256Key) //TODO: 這個換成rsa加密
}
//CheckJwtToken 檢查jwt是否有效
func CheckJwtToken(hs256Key []byte, jwtString string) (userClaims UserClaims, err error) {
_, err = jwt.ParseWithClaims(jwt