英文:
Why is my go handler not producing valid FormData?
问题
我正在尝试让一个使用Go编写的服务器对“mime/multipart”表单进行响应,但是遇到了问题。使用下面的代码,我得到了Uncaught (in promise) TypeError: Could not parse content as FormData.
的错误。
我的Go代码如下:
package main
import (
"log"
"mime/multipart"
"net/http"
)
func handler(resp http.ResponseWriter, req *http.Request) {
req.ParseMultipartForm(2097152)
mw := multipart.NewWriter(resp)
mw.WriteField("name", req.FormValue("user_name"))
mw.WriteField("email", req.FormValue("user_email"))
mw.WriteField("message", req.FormValue("user_message"))
resp.Header().Set("Content-Type", mw.FormDataContentType())
mw.Close()
}
func main() {
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
我的浏览器代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Your first HTML form</title>
<link rel="stylesheet" href="form.css">
</head>
<body>
<form name="theForm" method="post">
<ul>
<li>
<label for="name">Name:</label>
<input type="text" id="name" name="user_name">
</li>
<li>
<label for="mail">E-mail:</label>
<input type="email" id="mail" name="user_email">
</li>
<li>
<label for="msg">Message:</label>
<textarea id="msg" name="user_message"></textarea>
</li>
<li class="button">
<button type="submit">Send your message</button>
</li>
</ul>
</form>
<pre id="response"></pre>
<script>
const form = document.forms["theForm"];
form.addEventListener( 'submit', function ( event ) {
event.preventDefault();
const fd = new FormData(form);
fetch('/form-handler', {
method: 'POST',
body: fd
})
.then(response => response.formData())
.then(data => document.getElementById("response").innerText = JSON.stringify(data));
});
</script>
</body>
</html>
如果我将JavaScript代码更改为.then(response => response.text)
,我会得到看起来正确的响应,所以不确定是否缺少了结尾的CRLF或其他原因。
英文:
I'm tinkering around trying to get a server written in go to respond to a "mime/multipart" form with a "mime/multipart" form.
With the code below, I'm getting Uncaught (in promise) TypeError: Could not parse content as FormData.
My go looks like this:
package main
import (
"log"
"mime/multipart"
"net/http"
)
func handler(resp http.ResponseWriter, req *http.Request) {
req.ParseMultipartForm(2097152)
mw := multipart.NewWriter(resp)
mw.WriteField("name", req.FormValue("user_name"))
mw.WriteField("email", req.FormValue("user_email"))
mw.WriteField("message", req.FormValue("user_message"))
resp.Header().Set("Content-Type", mw.FormDataContentType())
mw.Close()
}
func main() {
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
My browser code looks like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Your first HTML form</title>
<link rel="stylesheet" href="form.css">
</head>
<body>
<form name="theForm" method="post">
<ul>
<li>
<label for="name">Name:</label>
<input type="text" id="name" name="user_name">
</li>
<li>
<label for="mail">E-mail:</label>
<input type="email" id="mail" name="user_email">
</li>
<li>
<label for="msg">Message:</label>
<textarea id="msg" name="user_message"></textarea>
</li>
<li class="button">
<button type="submit">Send your message</button>
</li>
</ul>
</form>
<pre id="response"></pre>
<script>
const form = document.forms["theForm"];
form.addEventListener( 'submit', function ( event ) {
event.preventDefault();
const fd = new FormData(form);
fetch('/form-handler', {
method: 'POST',
body: fd
})
.then(response => response.formData())
.then(data => document.getElementById("response").innerText = JSON.stringify(data));
});
</script>
</body>
</html>
If I change the JavaScript to .then(response => response.text)
, I get what looks like the right response, so not sure if there's a missing CRLF at the end or what?
答案1
得分: 3
你需要将resp.Header().Set("Content-Type", mw.FormDataContentType())
移到第一个写操作之前。像这样:
func handler(resp http.ResponseWriter, req *http.Request) {
req.ParseMultipartForm(2097152)
mw := multipart.NewWriter(resp)
resp.Header().Set("Content-Type", mw.FormDataContentType())
mw.WriteField("name", req.FormValue("user_name"))
mw.WriteField("email", req.FormValue("user_email"))
mw.WriteField("message", req.FormValue("user_message"))
mw.Close()
}
在对ResponseWriter
进行第一次写操作后,无法修改HTTP头。如果在那时没有设置Content-Type
,它将默认为Content-Type: text/plain; charset=utf-8
,而浏览器无法解析该类型,因为它需要在Content-Type
头中提供边界信息。
英文:
You have to move resp.Header().Set("Content-Type", mw.FormDataContentType())
to above the first write. Like so:
func handler(resp http.ResponseWriter, req *http.Request) {
req.ParseMultipartForm(2097152)
mw := multipart.NewWriter(resp)
resp.Header().Set("Content-Type", mw.FormDataContentType())
mw.WriteField("name", req.FormValue("user_name"))
mw.WriteField("email", req.FormValue("user_email"))
mw.WriteField("message", req.FormValue("user_message"))
mw.Close()
}
HTTP headers can't be modified after the first write to the ResponseWriter
. If no Content-Type
is set at that point it defaults to Content-Type: text/plain; charset=utf-8
which the browser can't parse since it needs the boundary which is given in the Content-Type
header
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论