59
49

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

FormData は multipart/form-data で application/x-www-form-urlencoded は URLSearchParams

Posted at

この記事は、今のところどのアドベントカレンダーにも属していません。

FormData

XHR2 での Form の POST などには、 FormData オブジェクトが使えます。
例えばこんな感じ。

<form id="fileUpload" name="fileUpload" method="post" action="/server">
 <input type="text" name="fileName" value="memo.txt">
 <input type="file" name="file">
 <input type="submit">
</form>

<script>
var fileUpload = document.getElementById('fileUpload');
fileUpload.addEventListener('submit', function(e) {
  e.preventDefault();
  var xhr = new XMLHttpRequest();
  xhr.open('POST', '/');
  xhr.send(new FormData(myform)); // ここ
});
</script>

もしくは Form を経由せずに自分で組み立てることもできます。

var form = new FormData();

// file のような blob
var file = new Blob(['this is my memo'], { type: "text/plain" });

form.append('fileName', 'memo.txt');
form.append('file', file);

xhr.send(form);

ところが、これはどちらかというと Blob や File を送ることを想定されているため、
FormData を send したら、 multipart/form-data として送られます。

それはまあ、いいのですが、例えば <input type="text"> のみの Form や、
テキストのみを append した FormData を送ったとしても、 multipart になってしまいます。

var form = new FormData();
form.append('id', '123456');
form.append('username', 'jxck');
xhr.send(form);


// ------WebKitFormBoundaryIieqlAAUtjBHtKc1
// Content-Disposition: form-data; name="id"
//
// 123456
// ------WebKitFormBoundaryIieqlAAUtjBHtKc1
// Content-Disposition: form-data; name="username"
//
// jxck
// ------WebKitFormBoundaryIieqlAAUtjBHtKc1--
// Response Headersview source

例え XHR に content-type のヘッダを追加していても form-urlencoded にはならず、
ちょっと直感に反する気がしてしまう。(かつ、 Twitter で検索したら同じことをつぶやいてる人はいる模様)

という話を ML で聞いてみたら、それは URLSearchParam でやれとのことだった。

[whatwg] why FormData dosen't support x-www-form-urlencoded ?

URLSearchParams

URL の query を組み立てるための API 的な感じ。

絶賛仕様策定中の URL spec の一部として定義されています。
(この話はまたどっかで)

var paramsString = "q=URLUtils.searchParams&topic=api";
var searchParams = new URLSearchParams(paramsString);

console.log(searchParams.has("topic") === true); // true
console.log(searchParams.get("topic") === "api"); // true
console.log(searchParams.getAll("topic")); // ["api"]
console.log(searchParams.get("foo") === null); // true
console.log(searchParams.append("topic", "webdev") === undefined);
console.log(searchParams.toString() === "q=URLUtils.searchParams&topic=api&topic=webdev");
console.log(searchParams.delete("topic") === undefined);
console.log(searchParams.toString() === "q=URLUtils.searchParams");

まあ、 API 自体は直感的というか。良い意味でなんでも無い感じ。

実装はまだ FireFox くらいしかないようなので、片手間に実装してみる。

Jxck / URLSearchParams.js

まとめ

でも、 getElementById で取得した Form をそのまま xhr.send() しても、 multipart/formdata になるのはちょっとなぁと思わなくはない。
サーバが対応してれば別にいいのだけれど、 OAuth 系とかそうじゃないものもある気がするし。

Form から一旦 input を取り出して、自分で URLSearchParams を組み立てて送るのもなぁ。
これをバグとして上げるべきかどうか、ご意見あれば頂きたいです。

59
49
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
59
49

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?