英文:
how to combine regular FormValue with multipart form data in Golang net/http Request
问题
我想在服务请求之前,从几个中间件处理函数中调用golang
net/http
Request
上的FormValue
方法。而且我不希望在执行此操作时使请求无效。
这个方法在除了当传入请求是multipart
form-data
时都能正常工作,但是在调用FormValue
之后,数据会变得无效,最终路由中没有可解析的内容。
英文:
I want to call FormValue
on golang
net/http
Request
from several middleware handler functions before serving the request. And I do not want to invalidate the request while doing this.
It works fine except when the incoming request has a multipart
form-data
, the data gets invalidated after I call FormValue
and there is nothing to parse in the final route.
答案1
得分: 4
我写了一个实用函数来解决我的问题:
package utils
import (
"bytes"
"io"
"io/ioutil"
"mime"
"mime/multipart"
"net/http"
"strings"
)
// 在不使请求体无效的情况下获取表单值,以防数据是多部分的
func GetFormValues(request *http.Request, keys []string) []string {
var values []string
mediaType, params, err := mime.ParseMediaType(request.Header.Get("Content-Type"))
if err != nil || !strings.HasPrefix(mediaType, "multipart/") {
for i := range keys {
values = append(values, request.FormValue(keys[i]))
}
} else { // 多部分表单
buf, _ := ioutil.ReadAll(request.Body)
origBody := ioutil.NopCloser(bytes.NewBuffer(buf))
var rdr = multipart.NewReader(bytes.NewBuffer(buf), params["boundary"])
for len(values) < len(keys) {
part, err_part := rdr.NextPart()
if err_part == io.EOF {
break
}
for i := range keys {
if part.FormName() == keys[i] {
buf := new(bytes.Buffer)
buf.ReadFrom(part)
values = append(values, buf.String())
}
}
}
request.Body = origBody
}
if len(values) == len(keys) {
return values
} else {
return nil
}
}
// 在不使请求体无效的情况下获取表单值
func GetFormValue(request *http.Request, key string) string {
if result := GetFormValues(request, []string{key}); len(result) == 1 {
return result[0]
} else {
return ""
}
}
现在,不再调用:
value := request.FormValue(key)
而是调用:
value := utils.GetFormValue(request, key)
或者对于多个值:
values := utils.GetFormValues(request, []string{keys...})
英文:
I wrote a utility function that solved my problem:
package utils
import (
"bytes"
"io"
"io/ioutil"
"mime"
"mime/multipart"
"net/http"
"strings"
)
// Get form values without invalidating the request body in case the data is multiform
func GetFormValues(request *http.Request, keys []string) []string {
var values []string
mediaType, params, err := mime.ParseMediaType(request.Header.Get("Content-Type"))
if err != nil || !strings.HasPrefix(mediaType, "multipart/") {
for i := range keys {
values = append(values, request.FormValue(keys[i]))
}
} else { // multi form
buf, _ := ioutil.ReadAll(request.Body)
origBody := ioutil.NopCloser(bytes.NewBuffer(buf))
var rdr = multipart.NewReader(bytes.NewBuffer(buf), params["boundary"])
for len(values) < len(keys) {
part, err_part := rdr.NextPart()
if err_part == io.EOF {
break
}
for i := range keys {
if part.FormName() == keys[i] {
buf := new(bytes.Buffer)
buf.ReadFrom(part)
values = append(values, buf.String())
}
}
}
request.Body = origBody
}
if len(values) == len(keys) {
return values
} else {
return nil
}
}
// Get form value without invalidating the request body in case the data is multiform
func GetFormValue(request *http.Request, key string) string {
if result := GetFormValues(request, []string{key}); len(result) == 1 {
return result[0]
} else {
return ""
}
}
Now instead of calling
value := request.FormValue(key)
I do
value := utils.GetFormValue(request, key)
or for multiple values
values := utils.GetFormValues(request, []string{keys...})
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论