为什么我的Go处理程序没有生成有效的FormData?

huangapple go评论92阅读模式
英文:

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 (
	&quot;log&quot;
	&quot;mime/multipart&quot;
	&quot;net/http&quot;
)

func handler(resp http.ResponseWriter, req *http.Request) {
	req.ParseMultipartForm(2097152)
	mw := multipart.NewWriter(resp)
	mw.WriteField(&quot;name&quot;, req.FormValue(&quot;user_name&quot;))
	mw.WriteField(&quot;email&quot;, req.FormValue(&quot;user_email&quot;))
	mw.WriteField(&quot;message&quot;, req.FormValue(&quot;user_message&quot;))
	resp.Header().Set(&quot;Content-Type&quot;, mw.FormDataContentType())
	mw.Close()
}

func main() {
	http.HandleFunc(&quot;/&quot;, handler)
	log.Fatal(http.ListenAndServe(&quot;:8080&quot;, nil))
}

My browser code looks like this:

&lt;!DOCTYPE html&gt;
&lt;html&gt;
	&lt;head&gt;
		&lt;meta charset=&quot;utf-8&quot; /&gt;
		&lt;title&gt;Your first HTML form&lt;/title&gt;
        &lt;link rel=&quot;stylesheet&quot; href=&quot;form.css&quot;&gt;
	&lt;/head&gt;

	&lt;body&gt;

&lt;form name=&quot;theForm&quot; method=&quot;post&quot;&gt;
 &lt;ul&gt;
  &lt;li&gt;
    &lt;label for=&quot;name&quot;&gt;Name:&lt;/label&gt;
    &lt;input type=&quot;text&quot; id=&quot;name&quot; name=&quot;user_name&quot;&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;label for=&quot;mail&quot;&gt;E-mail:&lt;/label&gt;
    &lt;input type=&quot;email&quot; id=&quot;mail&quot; name=&quot;user_email&quot;&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;label for=&quot;msg&quot;&gt;Message:&lt;/label&gt;
    &lt;textarea id=&quot;msg&quot; name=&quot;user_message&quot;&gt;&lt;/textarea&gt;
  &lt;/li&gt;
  &lt;li class=&quot;button&quot;&gt;
    &lt;button type=&quot;submit&quot;&gt;Send your message&lt;/button&gt;
  &lt;/li&gt;
 &lt;/ul&gt;
&lt;/form&gt;
      
      &lt;pre id=&quot;response&quot;&gt;&lt;/pre&gt;
      
&lt;script&gt;
const form = document.forms[&quot;theForm&quot;];

form.addEventListener( &#39;submit&#39;, function ( event ) {
  event.preventDefault();
  const fd = new FormData(form);
  fetch(&#39;/form-handler&#39;, {
    method: &#39;POST&#39;,
    body: fd
  })
  .then(response =&gt; response.formData())
  .then(data =&gt; document.getElementById(&quot;response&quot;).innerText = JSON.stringify(data));
});
  
  
&lt;/script&gt;

	&lt;/body&gt;
&lt;/html&gt;

If I change the JavaScript to .then(response =&gt; 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(&quot;Content-Type&quot;, 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(&quot;Content-Type&quot;, mw.FormDataContentType())
    mw.WriteField(&quot;name&quot;, req.FormValue(&quot;user_name&quot;))
    mw.WriteField(&quot;email&quot;, req.FormValue(&quot;user_email&quot;))
    mw.WriteField(&quot;message&quot;, req.FormValue(&quot;user_message&quot;))
    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

huangapple
  • 本文由 发表于 2022年1月22日 20:44:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/70812935.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定