Kratos - 使用指北

前言

  • Kratos是一个Go语言的微服务框架,由B站开源,用于构建高可用、高性能、可扩展的微服务。
  • 文档地址:https://go-kratos.dev/
  • 代码地址:https://github.com/go-kratos/kratos
  • 文档说明已经足够详细,本文主要是对文档中没有提到的一些问题进行补充,以及一些使用心得。
  • 这里是我在使用Kratos时写的一个Demo。里面会包含这部分使用的代码。

文件上传

在kratos中,API是使用proto文件定义的,所以我们不好直接在proto文件中定义文件上传的接口。

官方做法:

Service中使用原生的http服务:

  • 实现encoding.Codec接口
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    var _ encoding.Codec = FormCodec{}

    const (
    // Name is form codec name
    Name = "form-data"
    )

    type FormCodec struct {
    }

    func (f FormCodec) Marshal(v interface{}) ([]byte, error) {
    return nil, nil
    }

    func (f FormCodec) Unmarshal(data []byte, v interface{}) error {
    // todo 参数解析为结构体,或者直接不处理就返回
    return nil
    }

    func (f FormCodec) Name() string {
    return Name
    }
    实现FormCodec接口,然后在service中使用原生的http服务来处理文件上传。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    func (f FileUploadService) UploadFile(ctx context.Context, request *file_upload.UploadFileRequest) (*file_upload.UploadFileReply, error) {
    req, ok := http.RequestFromServerContext(ctx)
    if !ok {
    return nil, errors.New("http.RequestFromContext error")
    }
    // 设置内存大小
    err := req.ParseMultipartForm(32 << 20)
    if err != nil {
    return nil, err
    }
    fil := req.MultipartForm.File["file_content"]
    if len(fil) == 0 {
    return nil, errors.New("file_content is empty")
    }
    for _, header := range fil {
    // 打开文件
    file, err := header.Open()
    if err != nil {
    return nil, err
    }
    defer file.Close()
    }
    return &file_upload.UploadFileReply{}, nil
    }

重定向

  • 在官方文档中也有重定向的例子,但是是基于 中间件的方式来实现的。无法直接在业务中使用。
  • 并且其实在源码中有留下一个接口http.Redirect,但是没有实现。我这里就是用这个接口来实现重定向。

自定义 Encoder 方法

完整代码可以查看这里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
func MyResponseEncoder(w httpNet.ResponseWriter, r *httpNet.Request, v interface{}) error {
if v == nil {
return nil
}
if rd, ok := v.(http.Redirector); ok {
url, code := rd.Redirect()
httpNet.Redirect(w, r, url, code)
return nil
}
if asset, ok := v.(IMyResponseEncoderWrite); ok {
return handleIMyResponseEncoderWrite(w, asset)
}
reply := &BaseResponse{
Code: 0,
Msg: "ok",
Ts: time.Now().String(),
}
if m, ok := v.(proto.Message); ok {
payload, err := anypb.New(m)
if err != nil {
return err
}
reply.Data = payload
}

codec, _ := http.CodecForRequest(r, "Accept")
data, err := codec.Marshal(reply)
if err != nil {
return err
}
w.Header().Set("Content-Type", "application/json")
_, err = w.Write(data)
if err != nil {
return err
}
return nil
}

定义API接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
service RedirectService {
rpc Redirect (RedirectRequest) returns (RedirectReply) {
option (google.api.http) = {
get: "/api/v1/redirect",
};
}
}

message RedirectRequest {
string redirect_url = 2;
}

message RedirectReply {
// 跳转地址
string redirect_to = 1;
// 状态码
int32 status_code = 2;
}

API 实现 http.Redirect

1
2
3
4
5
var _ http.Redirector = (*RedirectReply)(nil)

func (s *RedirectReply) Redirect() (string, int) {
return s.RedirectTo, int(s.StatusCode)
}

重定向总结

  • 通过实现http.Redirector接口,可以在MyResponseEncoder中判断是否是重定向的接口,然后调用Redirect方法进行重定向。
  • 业务代码就可以在Service层中处理,并且通过API的方式来定义重定向的接口。
  • 相比于官方的中间件方式,这种方式更加灵活,可以在业务中直接使用。

错误处理

  • kratos 是用了 protoc-gen-go-errors 插件来生成错误码的。
  • 生成的错误码是一个枚举类型,每个错误码都有一个Code,Reason,Message。
  • Code 你可以自己定义,但是 Reason 和 Message 是根据你的 proto 文件中定义的错误码来生成的。
  • 在使用中,你需要通过 Reason 来判断错误,Message 是用来给用户看的。而 Code 是在不同场景下有不同的含义。

Kratos - 使用指北
https://blog.codefish.net/2024/10/06/golang-kratos-guide/
作者
CodeFish
发布于
2024年10月6日
许可协议