单体最佳实践的由来
QPSgo-zerogo-zerogo-zeroServicePodgo-zero单体示例
go-zerogo-zeroAPIgoctlOSSOSSgo-zeroAPIgoctlgo-zeroJWTGogo-zero单体实现
APIgo-zeroAPIRESTful APIgoctllogicdownloaduploadAPIDownload示例需求如下:
/static/apidownload.apisyntax = "v1"
type DownloadRequest {
File string `path:"file"`
}
service file-api {
@handler DownloadHandler
get /static/:file(DownloadRequest)
}zero-apisyntax = “v1”zero-apiv1type DownloadRequestDownloadservice file-apiDownloadUpload示例需求如下:
/uploadjsoncodeHTTP codeapiupload.apisyntax = "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-apiGoDownloadUpload定义单体服务接口
goctlAPIAPIapifile.apisyntax = "v1"
import "download.api"
import "upload.api"C/C++#includeDownloadUploadservice nameAPIserviceAPIDownloadUploadfile.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这里一共做了以下几件事:
Pathtype Config struct {
rest.RestConf
// 新增
Path string `json:",default=."`
}
- 调整了请求体的大小限制,如下:
Name: file-api
Host: localhost
Port: 8888
# 新增
MaxBytes: 1073741824DownloadResponseWriterio.Writerlogicfunc (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.Requestlogicfunc (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.yamlcurlDownload$ 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-zeroAPIdownload.apiupload.apiAPIfile.apiimportAPIgoctl api gogoctlSQLCRUDcache项目地址
go-zero微信交流群
关注『微服务实践』公众号并点击 交流群 获取社区群二维码。
go-zero