ホームページ >ウェブフロントエンド >jsチュートリアル >FormData を multipart/form-data 文字列に変換し、Response を使用して元に戻す
さまざまな値を ReadableStream に変換することに関する別の記事に取り組んでいるときに、FormData を multipart/form-data 文字列に変換し、Response を使用して戻すという巧妙なトリックを発見しました。驚くべきことに、FormData はそのままではこの機能を提供しません。ただし、Response のメソッドを活用することで、これを非常に簡単に達成できます。
ChatGPT (4o と o1-preview の両方) から支援を得ようとしたこともありましたが、たとえヒントがあっても、この解決策を提案したり合成したりすることはできませんでした。 Google検索でも結果は出ませんでした。私は独自性を主張しませんが、このアプローチは知られていない、またはほとんど知られていないようです。このような変換機能は、Response API の作成者によって意図的に設計されたものではないと思います。それはむしろ副作用であり、それが解決策をさらに興味深いものにしています。そこで、私は自分の発見を共有するためにこの記事を書くことにしました。
FormData のインスタンスがあると仮定しましょう:
const formData = new FormData(); formData.set('value', 123); formData.set( 'myfile', new File(['{"hello":"world"}'], 'demo.json', { type: 'application/json' }) );
私たちの目標は、この FormData インスタンスから multipart/form-data 文字列を取得することです。一般的な提案には、手動で FormData を文字列にシリアル化するか、Request 経由で複雑な操作を実行するか、そのためのライブラリを使用することが含まれます。ただし、本文として FormData を受け入れる Response コンストラクターを単純に使用し、その text() メソッドを呼び出して目的の文字列表現を取得することもできます。
// FormData -> multipart/form-data string function convertFormDataToMultipartString(formData) { return new Response(formData).text(); } const multipartString = await convertFormDataToMultipartString(formData); console.log(multipartString); // Example output: // ------WebKitFormBoundaryQi7NBNu0nAmyAhpU // Content-Disposition: form-data; name="value" // // 123 // ------WebKitFormBoundaryQi7NBNu0nAmyAhpU // Content-Disposition: form-data; name="myfile"; filename="demo.json" // Content-Type: application/json // // {"hello":"world"} // ------WebKitFormBoundaryQi7NBNu0nAmyAhpU--
必要に応じて、Content-Type ヘッダーや境界などの追加の値を抽出することもできます。
// FormData -> multipart/form-data async function convertFormDataToMultipart(formData) { const response = new Response(formData); const contentType = response.headers.get('Content-Type'); const boundary = contentType.match(/boundary=(\S+)/)[1]; return { contentType, boundary, body: await response.text(), }; } const multipart = await convertFormDataToMultipart(formData); console.log(multipart); // { // contentType: 'multipart/form-data; boundary=----WebKitFormBoundarybfJIH5LgEGPqNcqt', // boundary: '----WebKitFormBoundarybfJIH5LgEGPqNcqt', // body: '------WebKitFormBoundarybfJIH5LgEGPqNcqt\r\n...' // }
text() を使用する代わりに、arrayBuffer() などの他のメソッドを使用して、FormData のエンコードされたコンテンツを ArrayBuffer として取得することもできます。このタイプの値の利点は、転送可能なオブジェクトであり、postMessage() を使用してワーカー間で効率的に転送できることです (文字列とは異なり、コピーする必要がないという意味です)。 FormData オブジェクト自体は転送できません。
プロセスを逆にするには、再び Response を利用しますが、今回はその formData() メソッドを使用します。このメソッドの重要な点は、正しい Content-Type ヘッダーが必要であることです。このヘッダーには、multipart/form-data タイプと、パーツを区切るために使用される境界が含まれている必要があります。境界値がある場合は、それをヘッダーに挿入できます。ただし、マルチパート文字列だけがあり、他には何もない場合もあります。その場合、正規表現を使用して文字列から境界を抽出できます。
// multipart/form-data string -> FormData async function convertMultipartStringToFormData(multipartString) { const boundary = multipartString.match(/^\s*--(\S+)/)[1]; return new Response(multipartString, { headers: { // Without the correct header, the string won't be parsed, // and an exception will be thrown on formData() call 'Content-Type': 'multipart/form-data; boundary=' + boundary, }, }).formData(); } const restoredFormData = await convertMultipartStringToFormData(multipartString); console.log([...restoredFormData]); // [ // ['value', '123'], // ['myfile', File] // ]
FormData のシリアル化と同様に、文字列だけでなく ArrayBuffer、TypedArray、ReadableStream も FormData に変換できます。これは、Response がそのような値を本文の値として受け入れるためです。
潜在的な欠点の 1 つは、どちらのタイプの変換も非同期操作であることです。それ以外では、このメソッドは非常に信頼性が高く、デバッグに使用したり、 fetch() の外部で変換が必要な場合に使用できます。
このメソッドは幅広いブラウザーをサポートしています (2017 年以降にリリースされたすべてのブラウザーで動作するはずです)。このメソッドは、Response オブジェクトをサポートしている場合 (つまり、 fetch() が利用可能なバージョン)、Node.js、Deno、および Bun にも適用できます。
このアプローチが私と同じように興味深いと思っていただければ幸いです。これは、Response API の機能を利用して、FormData をマルチパート/フォームデータ文字列 (文字列だけでなく) に変換したり、逆に変換したりするためのシンプルかつ効果的な方法です。何か考えがある場合、または同じ結果を達成する他の方法を知っている場合は、お気軽にコメントで共有してください!
以上がFormData を multipart/form-data 文字列に変換し、Response を使用して元に戻すの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。