单体最佳实践的由来
QPSgo-zero
go-zero
go-zeroServicePod
go-zero
单体示例
go-zero
go-zeroAPIgoctlOSSOSSgo-zeroAPIgoctlgo-zeroJWT
Gogo-zero
单体实现
API
go-zeroAPIRESTful APIgoctllogicdownloaduploadAPI
Download
示例需求如下:
/static/
apidownload.api
syntax = "v1"
type DownloadRequest {
File string `path:"file"`
}
service file-api {
@handler DownloadHandler
get /static/:file(DownloadRequest)
}
zero-api
syntax = “v1”zero-apiv1type DownloadRequestDownloadservice file-apiDownload
Upload
示例需求如下:
/uploadjsoncodeHTTP code
apiupload.api
syntax = "v1"
type UploadResponse {
Code int `json:"code"`
}
service file-api {
@handler UploadHandler
post /upload returns (UploadResponse)
}
解释如下:
syntax = “v1”zero-apiv1type UploadResponseUploadservice file-apiUpload
问题来了
DownloadUpload
不知道细心的你有没注意到一些细节:
DownloadUploadrequestresponseRequestResponsedownload.apiupload.apiservicefile-apiservice namedownload-apiupload-api
GoDownloadUpload
定义单体服务接口
goctlAPIAPI
apifile.api
syntax = "v1"
import "download.api"
import "upload.api"
C/C++#includeDownloadUpload
service name
APIserviceAPIDownloadUploadfile.api
至此,我们的文件结构如下:
.
└── api
├── download.api
├── file.api
└── upload.api
生成单体服务
APIgo-zeroAPIgoctl
$ goctl api go -api api/file.api -dir .
我们来看看生成后的文件结构:
.
├── api
│ ├── download.api
│ ├── file.api
│ └── upload.api
├── etc
│ └── file-api.yaml
├── file.go
├── go.mod
├── go.sum
└── internal
├── config
│ └── config.go
├── handler
│ ├── downloadhandler.go
│ ├── routes.go
│ └── uploadhandler.go
├── logic
│ ├── downloadlogic.go
│ └── uploadlogic.go
├── svc
│ └── servicecontext.go
└── types
└── types.go
我们来按目录解释一下项目代码的构成:
apiAPIetcyamlfile-api.yamlfile.gomainservice-apiinternal/configinternal/handlerAPIhandlerinternal/logichandlerlogicHTTP requestsRPC serviceinternal/svcmainServiceContexthandlerlogicinternal/typesAPI
咱们什么也不改,先来跑一下看看效果。
$ go run file.go -f etc/file-api.yaml
Starting server at 0.0.0.0:8888...
实现业务逻辑
logic
这里一共做了以下几件事:
Path
type Config struct {
rest.RestConf
// 新增
Path string `json:",default=."`
}
-
调整了请求体的大小限制,如下:
Name: file-api
Host: localhost
Port: 8888
# 新增
MaxBytes: 1073741824
DownloadResponseWriterio.Writerlogic
func (l *DownloadLogic) Download(req *types.DownloadRequest) error {
logx.Infof("download %s", req.File)
body, err := ioutil.ReadFile(req.File)
if err != nil {
return err
}
n, err := l.writer.Write(body)
if err != nil {
return err
}
if n < len(body) {
return io.ErrClosedPipe
}
return nil
}
Uploadhttp.Requestlogic
func (l *UploadLogic) Upload() (resp *types.UploadResponse, err error) {
l.r.ParseMultipartForm(maxFileSize)
file, handler, err := l.r.FormFile("myFile")
if err != nil {
return nil, err
}
defer file.Close()
logx.Infof("upload file: %+v, file size: %d, MIME header: %+v",
handler.Filename, handler.Size, handler.Header)
tempFile, err := os.Create(path.Join(l.svcCtx.Config.Path, handler.Filename))
if err != nil {
return nil, err
}
defer tempFile.Close()
io.Copy(tempFile, file)
return &types.UploadResponse{
Code: 0,
}, nil
}
file
$ go run file.go -f etc/file-api.yaml
curlDownload
$ curl -i "http://localhost:8888/static/file.go"
HTTP/1.1 200 OK
Traceparent: 00-831431c47d162b4decfb6b30fb232556-dd3b383feb1f13a9-00
Date: Mon, 25 Apr 2022 01:50:58 GMT
Content-Length: 584
Content-Type: text/plain; charset=utf-8
...
upload.htmlUpload
单体开发的总结
go-zero
APIdownload.apiupload.apiAPIfile.apiimportAPIgoctl api go
goctlSQLCRUDcache
项目地址
go-zero
微信交流群
关注『微服务实践』公众号并点击 交流群 获取社区群二维码。