转到网络服务 - POST tar.gz 文件作为请求 body
Go web service - POST tar.gz file as request body
我需要在处理 tar.gz 文件的 go 中实现 Web 服务,我想知道什么是正确的方法,我需要定义什么内容类型等。
此外,我发现很多事情都是自动处理的 - 在客户端,我只是 post gzip reader 作为请求 body 和 Accept-Encoding: gzip
header 是自动添加的,在服务器端 - 我不需要 gunzip 请求 body,它已经解压缩到 tar。那有意义吗?
我可以相信任何客户都会这样吗?
服务器:
func main() {
router := mux.NewRouter().StrictSlash(true)
router.Handle("/results", dataupload.NewUploadHandler()).Methods("POST")
log.Fatal(http.ListenAndServe(*address, router))
}
上传者:
package dataupload
import (
"errors"
log "github.com/Sirupsen/logrus"
"io"
"net/http"
)
// UploadHandler responds to /results http request, which is the result-service rest API for uploading results
type UploadHandler struct {
uploader Uploader
}
// NewUploadHandler creates UploadHandler instance
func NewUploadHandler() *UploadHandler {
return &UploadHandler{
uploader: TarUploader{},
}
}
func (uh UploadHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
retStatus := http.StatusOK
body, err := getBody(request)
if err != nil {
retStatus = http.StatusBadRequest
log.Error("Error fetching request body. ", err)
} else {
_, err := uh.uploader.Upload(body)
}
writer.WriteHeader(retStatus)
}
func getBody(request *http.Request) (io.ReadCloser, error) {
requestBody := request.Body
if requestBody == nil {
return nil, errors.New("Empty request body")
}
var err error
// this part is commented out since somehow the body is already gunzipped - no need to extract it.
/*if strings.Contains(request.Header.Get("Accept-Encoding"), "gzip") {
requestBody, err = gzip.NewReader(requestBody)
}*/
return requestBody, err
}
客户端
func main() {
f, err := os.Open("test.tar.gz")
if err != nil {
log.Fatalf("error openning file %s", err)
}
defer f.Close()
client := new(http.Client)
reader, err := gzip.NewReader(f)
if err != nil {
log.Fatalf("error gzip file %s", err)
}
request, err := http.NewRequest("POST", "http://localhost:8080/results", reader)
_, err = client.Do(request)
if err != nil {
log.Fatalf("error uploading file %s", err)
}
}
显然不是,但也许...
Golang 为http 客户端(和服务器)提供了很好的支持。这是第一种支持 http2 的语言,API 的设计清楚地表明了他们对快速 http 的关注。
这就是他们自动添加 Accept-Econding: gzip
的原因。这将大大减少服务器响应的大小,然后优化传输。
但 gzip 仍然是 http 1 中的一个选项,并非所有客户端都会将此 header 推送到您的服务器。
请注意,Content-Type
描述了您要发送的数据类型(这里是 tar.gz,但也可能是 application/json
、test/javascript
、...),当Accept-Encoding
描述了传输数据的编码方式
Go 会为你透明地处理 Accept-Encoding
因为它负责数据的传输。然后由您来处理 Content-Type
因为只有您知道如何理解您收到的内容
您为客户端编写的代码只是直接发送 tarfile,因为这段代码:
reader, err := gzip.NewReader(f)
...
request, err := http.NewRequest("POST", "http://localhost:8080/results", reader)
如果您直接发送 .tar.gz
文件内容,那么您 将 需要将其压缩到服务器上。例如:
request, err := http.NewRequest(..., f)
我认为这更接近您期望第三方客户端表现出的行为。
我需要在处理 tar.gz 文件的 go 中实现 Web 服务,我想知道什么是正确的方法,我需要定义什么内容类型等。
此外,我发现很多事情都是自动处理的 - 在客户端,我只是 post gzip reader 作为请求 body 和 Accept-Encoding: gzip
header 是自动添加的,在服务器端 - 我不需要 gunzip 请求 body,它已经解压缩到 tar。那有意义吗?
我可以相信任何客户都会这样吗?
服务器:
func main() {
router := mux.NewRouter().StrictSlash(true)
router.Handle("/results", dataupload.NewUploadHandler()).Methods("POST")
log.Fatal(http.ListenAndServe(*address, router))
}
上传者:
package dataupload
import (
"errors"
log "github.com/Sirupsen/logrus"
"io"
"net/http"
)
// UploadHandler responds to /results http request, which is the result-service rest API for uploading results
type UploadHandler struct {
uploader Uploader
}
// NewUploadHandler creates UploadHandler instance
func NewUploadHandler() *UploadHandler {
return &UploadHandler{
uploader: TarUploader{},
}
}
func (uh UploadHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
retStatus := http.StatusOK
body, err := getBody(request)
if err != nil {
retStatus = http.StatusBadRequest
log.Error("Error fetching request body. ", err)
} else {
_, err := uh.uploader.Upload(body)
}
writer.WriteHeader(retStatus)
}
func getBody(request *http.Request) (io.ReadCloser, error) {
requestBody := request.Body
if requestBody == nil {
return nil, errors.New("Empty request body")
}
var err error
// this part is commented out since somehow the body is already gunzipped - no need to extract it.
/*if strings.Contains(request.Header.Get("Accept-Encoding"), "gzip") {
requestBody, err = gzip.NewReader(requestBody)
}*/
return requestBody, err
}
客户端
func main() {
f, err := os.Open("test.tar.gz")
if err != nil {
log.Fatalf("error openning file %s", err)
}
defer f.Close()
client := new(http.Client)
reader, err := gzip.NewReader(f)
if err != nil {
log.Fatalf("error gzip file %s", err)
}
request, err := http.NewRequest("POST", "http://localhost:8080/results", reader)
_, err = client.Do(request)
if err != nil {
log.Fatalf("error uploading file %s", err)
}
}
显然不是,但也许...
Golang 为http 客户端(和服务器)提供了很好的支持。这是第一种支持 http2 的语言,API 的设计清楚地表明了他们对快速 http 的关注。
这就是他们自动添加 Accept-Econding: gzip
的原因。这将大大减少服务器响应的大小,然后优化传输。
但 gzip 仍然是 http 1 中的一个选项,并非所有客户端都会将此 header 推送到您的服务器。
请注意,Content-Type
描述了您要发送的数据类型(这里是 tar.gz,但也可能是 application/json
、test/javascript
、...),当Accept-Encoding
描述了传输数据的编码方式
Go 会为你透明地处理 Accept-Encoding
因为它负责数据的传输。然后由您来处理 Content-Type
因为只有您知道如何理解您收到的内容
您为客户端编写的代码只是直接发送 tarfile,因为这段代码:
reader, err := gzip.NewReader(f)
...
request, err := http.NewRequest("POST", "http://localhost:8080/results", reader)
如果您直接发送 .tar.gz
文件内容,那么您 将 需要将其压缩到服务器上。例如:
request, err := http.NewRequest(..., f)
我认为这更接近您期望第三方客户端表现出的行为。