使用golang实现websocket消息推送

需求

每隔几秒主动调用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(jwtString, 

你可能感兴趣的:(websocket,golang,rabbitmq,docker)