この記事は、今のところどのアドベントカレンダーにも属していません。
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 くらいしかないようなので、片手間に実装してみる。
まとめ
でも、 getElementById で取得した Form をそのまま xhr.send() しても、 multipart/formdata になるのはちょっとなぁと思わなくはない。
サーバが対応してれば別にいいのだけれど、 OAuth 系とかそうじゃないものもある気がするし。
Form から一旦 input を取り出して、自分で URLSearchParams を組み立てて送るのもなぁ。
これをバグとして上げるべきかどうか、ご意見あれば頂きたいです。