Hertz
本文最后更新于 2024-04-02,文章内容可能已经过时。
Hertz
1.简介:
2.Hertz分层设计:
3.特点:
微服务超 10 万、跨语言场景,字节服务网格依靠 CloudWeGo 扛住流量洪峰 (qq.com)
4.新特性:
5.提问截图:
6.使用:
依据快速开始 | CloudWeGo此教程学习.
6.1 安装:
cmd,git,powershell的区别?
安装报错:
解决方案:
|
|
6.2 goland配置:
全部爆红,识别不出来,同步也同步不了.
解决方案是设置代理.
(181条消息) Goland 下载 go 包_JikeStardy的博客-CSDN博客
解决方案从这个文章找到,略有修改.
|
|
可能会出现版本不匹配的情况.建议切换到1.19版本.
|
|
6.3 hello world:
尝试编写一个类似于spring中,controller层的一个接口的一个简单的方法.
只需要一个main方法。
|
|
6.4 获取参数:
|
|
6.5 hertz+gorm 实现简单的MVC逻辑:
也是只需要main函数.
|
|
6.6 hertz+kitex+gorm实现douyin基础功能:
6.6.1user-server:
rpc的服务端.只被系统内调用.
package main
import (
"context"
"crypto/sha256"
"douyin/kitex_gen/api"
"encoding/hex"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"math/big"
)
// UserImpl implements the last service interface defined in the IDL.
type UserImpl struct{}
type User struct {
Id int64 `gorm:"column:id;"`
UserId int64 `gorm:"column:user_id;"`
Username string `gorm:"column:username;"`
Password string `gorm:"column:password;"`
Name string `gorm:"column:name;"`
Avatar string `gorm:"column:avatar;"`
BackgroundImage string `gorm:"column:background_image;"`
Signature string `gorm:"column:signature;"`
}
func (u *User) TableName() string {
return "user"
}
// 全局盐
var salt = "byteDanceAgain"
// 字符串hash,用于加密密码
func hashTo15Bits(input string) string {
// 创建一个SHA-256哈希对象
h := sha256.New()
// 将字符串输入写入哈希对象
_, err := h.Write([]byte(input))
if err != nil {
panic(err)
}
// 获取SHA-256哈希值的字节数组
hashBytes := h.Sum(nil)
// 取哈希值的前两个字节并转换为16进制字符串
hashHex := hex.EncodeToString(hashBytes[:2])
return hashHex
}
// 用户id生成哈希,根据账号和
func hashToI64(input string) int64 {
// 创建一个SHA-256哈希对象
h := sha256.New()
// 将字符串输入写入哈希对象
_, err := h.Write([]byte(input))
if err != nil {
panic(err)
}
// 获取SHA-256哈希值的字节数组
hashBytes := h.Sum(nil)
// 将哈希值的前8个字节转换为int64
var hashInt big.Int
hashInt.SetBytes(hashBytes[:8])
result := hashInt.Int64()
return result
}
// Register implements the UserImpl interface.
func (s *UserImpl) Register(ctx context.Context, req *api.RegisterRequest) (resp *api.RegisterResponse, err error) {
///建立数据库连接,数据库名:数据库密码
dsn := "root:123456@tcp(127.0.0.1:3306)/dbgotest"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
return nil, err
}
//判断用户名是否唯一
var user User
db.First(&user, "username = ?", req.Username)
if user.Id != 0 {
resp = &api.RegisterResponse{Code: "1", Msg: "用户名已经存在!"}
return
}
//对密码加盐,加密存储进入数据库
password := hashTo15Bits(salt + req.Password)
fmt.Print(password)
//生成用户id
UserId := hashToI64(req.Username + req.Password)
fmt.Print(UserId)
//创建一条数据,传入一个对象
db.Create(&User{Username: req.Username, Password: password, Name: req.Name, UserId: UserId})
resp = &api.RegisterResponse{Code: "0", Msg: "用户注册成功!", Userid: UserId}
return
}
// Login implements the UserImpl interface.
func (s *UserImpl) Login(ctx context.Context, req *api.LoginRequest) (resp *api.LoginResponse, err error) {
///建立数据库连接,数据库名:数据库密码
dsn := "root:123456@tcp(127.0.0.1:3306)/dbgotest"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
return nil, err
}
var user User
db.First(&user, "username = ?", req.Username)
if user.Id == 0 {
resp = &api.LoginResponse{Code: "1", Msg: "用户不存在!"}
return
}
//验证密码
hashPassword := hashTo15Bits(salt + req.Password)
if user.Password != hashPassword {
resp = &api.LoginResponse{Code: "1", Msg: "用户密码错误!"}
return
}
resp = &api.LoginResponse{Code: "0", Msg: "用户登录成功!", Userid: user.Id}
return
}
// Get implements the UserImpl interface.
func (s *UserImpl) Get(ctx context.Context, req *api.GetInfoRequest) (resp *api.GetInfoResponse, err error) {
///建立数据库连接,数据库名:数据库密码
dsn := "root:123456@tcp(127.0.0.1:3306)/dbgotest"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
return nil, err
}
//获取用户信息
var user User
db.First(&user, "user_id = ?", req.Userid)
resp = &api.GetInfoResponse{Userid: user.UserId, Name: user.Name, Avatar: user.Avatar, BackgroundImage: user.BackgroundImage, Signature: user.Signature}
return
}
//批量获取用户信息
// GetAll implements the UserImpl interface.
func (s *UserImpl) GetAll(ctx context.Context, req *api.GetAllInfoResponse) (resp *api.GetAllInfoResponse, err error) {
dsn := "root:123456@tcp(127.0.0.1:3306)/dbgotest"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
return nil, err
}
var User1 []User
list := req.UserList
for i := 0; i < len(list); i++ {
db.First(&User1[i], "user_id = ?", list[i])
}
resp = &api.GetAllInfoResponse{UserList: User1}
return
}
6.6.2 user-client:
http访问接口,调用user-server,与前端进行交互.
// Code generated by hertz generator.
package main
import (
"context"
"douyin/kitex_gen/api"
"douyin/kitex_gen/api/user"
"fmt"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/protocol/consts"
"github.com/cloudwego/kitex/client"
"github.com/cloudwego/kitex/client/callopt"
"github.com/golang-jwt/jwt/v4"
"log"
"time"
)
type User struct {
Id int64 `gorm:"column:id;"`
UserId int64 `gorm:"column:user_id;"`
Username string `gorm:"column:username;"`
Password string `gorm:"column:password;"`
Name string `gorm:"column:name;"`
Avatar string `gorm:"column:avatar;"`
BackgroundImage string `gorm:"column:background_image;"`
Signature string `gorm:"column:signature;"`
}
// 定义一个密钥,用于签名和验证JWT
var jwtKey = []byte("byteDanceAgain")
// 使用hertz集成的jwt出现问题,故使用另一个jwt
// 创建一个JWT令牌
func createJWTToken(username string, password string, userId int64) (string, error) {
// 创建一个JWT声明
claims := jwt.MapClaims{
"Username": username,
"Password": password,
"UserId": userId,
"exp": time.Now().Add(time.Hour * 24).Unix(), // 设置过期时间为24小时
}
// 创建一个JWT令牌对象
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// 使用密钥签名JWT令牌
tokenString, err := token.SignedString(jwtKey)
if err != nil {
return "", err
}
return tokenString, nil
}
// 解析并验证JWT令牌
func parseJWTToken(tokenString string) (*jwt.MapClaims, error, int64) {
// 解析JWT令牌
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
// 验证签名方法
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return jwtKey, nil
})
if err != nil {
return nil, err, 0
}
// 验证JWT令牌的有效性
if !token.Valid {
return nil, fmt.Errorf("invalid token"), 0
}
// 获取声明中的信息
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
return nil, fmt.Errorf("couldn't parse claims"), 0
}
userID, ok := claims["UserID"].(int64)
if !ok {
return nil, fmt.Errorf("couldn't parse UserID"), 0
}
return &claims, nil, userID
}
func main() {
h := server.Default(server.WithHostPorts("127.0.0.1:8080"))
newClient, err := user.NewClient("user-server", client.WithHostPorts("127.0.0.1:8888"))
if err != nil {
log.Fatal(err)
}
//用户注册
h.POST("/user/register", func(c context.Context, ctx *app.RequestContext) {
username1 := ctx.Query("username")
password1 := ctx.Query("password")
name := ctx.Query("name")
req := &api.RegisterRequest{
Username: username1,
Password: password1,
Name: name,
}
resp, err := newClient.Register(context.Background(), req, callopt.WithRPCTimeout(3*time.Second))
if err != nil {
ctx.String(consts.StatusInternalServerError, "rpc链路失效!")
}
ctx.String(consts.StatusOK, resp.Code, resp.Msg, resp.Userid)
})
//用户登录
h.POST("/user/login", func(c context.Context, ctx *app.RequestContext) {
username1 := ctx.Query("username")
password1 := ctx.Query("password")
req := &api.LoginRequest{
Username: username1,
Password: password1,
}
resp, err := newClient.Login(context.Background(), req, callopt.WithRPCTimeout(3*time.Second))
if err != nil {
ctx.String(consts.StatusInternalServerError, "rpc链路失效!")
}
//判断是否登录成功
if resp.Code != "0" {
ctx.String(consts.StatusInternalServerError, "登录失败!")
}
//生成token
token, nil := createJWTToken(username1, password1, resp.Userid)
if err != nil {
ctx.String(consts.StatusInternalServerError, "token生成失败!")
}
ctx.String(consts.StatusOK, resp.Code, resp.Msg, resp.Userid, token)
})
//获取用户信息
h.POST("/user/getUser", func(c context.Context, ctx *app.RequestContext) {
userId := ctx.GetInt64("userId")
token1 := ctx.Query("token")
//进行token解析
_, err, userId1 := parseJWTToken(token1)
if err != nil {
ctx.String(consts.StatusInternalServerError, "token错误!")
}
//传入的userid和token所代表的的用户可能不是同一个,所以不需要进行验证,只需要token本身正确即可.
//if userId1 != userId {
// ctx.String(consts.StatusInternalServerError, "token与用户id不匹配!")
//}
req := &api.GetInfoRequest{
Userid: userId,
}
resp, err := newClient.Get(context.Background(), req, callopt.WithRPCTimeout(3*time.Second))
if err != nil {
ctx.String(consts.StatusInternalServerError, "rpc链路失效!")
}
ctx.String(consts.StatusOK, "获取用户信息成功!", resp.Userid, resp.Name, resp.Avatar, resp.BackgroundImage)
})
h.Spin()
}
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果