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

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

Why is my go handler not producing valid FormData?

问题

我正在尝试让一个使用Go编写的服务器对“mime/multipart”表单进行响应,但是遇到了问题。使用下面的代码,我得到了Uncaught (in promise) TypeError: Could not parse content as FormData.的错误。

我的Go代码如下:

  1. package main
  2. import (
  3. "log"
  4. "mime/multipart"
  5. "net/http"
  6. )
  7. func handler(resp http.ResponseWriter, req *http.Request) {
  8. req.ParseMultipartForm(2097152)
  9. mw := multipart.NewWriter(resp)
  10. mw.WriteField("name", req.FormValue("user_name"))
  11. mw.WriteField("email", req.FormValue("user_email"))
  12. mw.WriteField("message", req.FormValue("user_message"))
  13. resp.Header().Set("Content-Type", mw.FormDataContentType())
  14. mw.Close()
  15. }
  16. func main() {
  17. http.HandleFunc("/", handler)
  18. log.Fatal(http.ListenAndServe(":8080", nil))
  19. }

我的浏览器代码如下:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8" />
  5. <title>Your first HTML form</title>
  6. <link rel="stylesheet" href="form.css">
  7. </head>
  8. <body>
  9. <form name="theForm" method="post">
  10. <ul>
  11. <li>
  12. <label for="name">Name:</label>
  13. <input type="text" id="name" name="user_name">
  14. </li>
  15. <li>
  16. <label for="mail">E-mail:</label>
  17. <input type="email" id="mail" name="user_email">
  18. </li>
  19. <li>
  20. <label for="msg">Message:</label>
  21. <textarea id="msg" name="user_message"></textarea>
  22. </li>
  23. <li class="button">
  24. <button type="submit">Send your message</button>
  25. </li>
  26. </ul>
  27. </form>
  28. <pre id="response"></pre>
  29. <script>
  30. const form = document.forms["theForm"];
  31. form.addEventListener( 'submit', function ( event ) {
  32. event.preventDefault();
  33. const fd = new FormData(form);
  34. fetch('/form-handler', {
  35. method: 'POST',
  36. body: fd
  37. })
  38. .then(response => response.formData())
  39. .then(data => document.getElementById("response").innerText = JSON.stringify(data));
  40. });
  41. </script>
  42. </body>
  43. </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:

  1. package main
  2. import (
  3. &quot;log&quot;
  4. &quot;mime/multipart&quot;
  5. &quot;net/http&quot;
  6. )
  7. func handler(resp http.ResponseWriter, req *http.Request) {
  8. req.ParseMultipartForm(2097152)
  9. mw := multipart.NewWriter(resp)
  10. mw.WriteField(&quot;name&quot;, req.FormValue(&quot;user_name&quot;))
  11. mw.WriteField(&quot;email&quot;, req.FormValue(&quot;user_email&quot;))
  12. mw.WriteField(&quot;message&quot;, req.FormValue(&quot;user_message&quot;))
  13. resp.Header().Set(&quot;Content-Type&quot;, mw.FormDataContentType())
  14. mw.Close()
  15. }
  16. func main() {
  17. http.HandleFunc(&quot;/&quot;, handler)
  18. log.Fatal(http.ListenAndServe(&quot;:8080&quot;, nil))
  19. }

My browser code looks like this:

  1. &lt;!DOCTYPE html&gt;
  2. &lt;html&gt;
  3. &lt;head&gt;
  4. &lt;meta charset=&quot;utf-8&quot; /&gt;
  5. &lt;title&gt;Your first HTML form&lt;/title&gt;
  6. &lt;link rel=&quot;stylesheet&quot; href=&quot;form.css&quot;&gt;
  7. &lt;/head&gt;
  8. &lt;body&gt;
  9. &lt;form name=&quot;theForm&quot; method=&quot;post&quot;&gt;
  10. &lt;ul&gt;
  11. &lt;li&gt;
  12. &lt;label for=&quot;name&quot;&gt;Name:&lt;/label&gt;
  13. &lt;input type=&quot;text&quot; id=&quot;name&quot; name=&quot;user_name&quot;&gt;
  14. &lt;/li&gt;
  15. &lt;li&gt;
  16. &lt;label for=&quot;mail&quot;&gt;E-mail:&lt;/label&gt;
  17. &lt;input type=&quot;email&quot; id=&quot;mail&quot; name=&quot;user_email&quot;&gt;
  18. &lt;/li&gt;
  19. &lt;li&gt;
  20. &lt;label for=&quot;msg&quot;&gt;Message:&lt;/label&gt;
  21. &lt;textarea id=&quot;msg&quot; name=&quot;user_message&quot;&gt;&lt;/textarea&gt;
  22. &lt;/li&gt;
  23. &lt;li class=&quot;button&quot;&gt;
  24. &lt;button type=&quot;submit&quot;&gt;Send your message&lt;/button&gt;
  25. &lt;/li&gt;
  26. &lt;/ul&gt;
  27. &lt;/form&gt;
  28. &lt;pre id=&quot;response&quot;&gt;&lt;/pre&gt;
  29. &lt;script&gt;
  30. const form = document.forms[&quot;theForm&quot;];
  31. form.addEventListener( &#39;submit&#39;, function ( event ) {
  32. event.preventDefault();
  33. const fd = new FormData(form);
  34. fetch(&#39;/form-handler&#39;, {
  35. method: &#39;POST&#39;,
  36. body: fd
  37. })
  38. .then(response =&gt; response.formData())
  39. .then(data =&gt; document.getElementById(&quot;response&quot;).innerText = JSON.stringify(data));
  40. });
  41. &lt;/script&gt;
  42. &lt;/body&gt;
  43. &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())移到第一个写操作之前。像这样:

  1. func handler(resp http.ResponseWriter, req *http.Request) {
  2. req.ParseMultipartForm(2097152)
  3. mw := multipart.NewWriter(resp)
  4. resp.Header().Set("Content-Type", mw.FormDataContentType())
  5. mw.WriteField("name", req.FormValue("user_name"))
  6. mw.WriteField("email", req.FormValue("user_email"))
  7. mw.WriteField("message", req.FormValue("user_message"))
  8. mw.Close()
  9. }

在对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:

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

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:

确定