前書き
前回の記事「フォームフォームからフロントエンドデータとバックエンドデータのやりとりについて話そう」では、ブラウザとサーバー間の接続の一部を説明しましたが、フォームフォームについてはある程度マスターできたようです。 、しかし現実は残酷です、私は前の記事でクリックしたばかりのフォームフォームに関する大きな知識があることを最近のプロジェクトで発見しました。このコンテンツ、つまりファイルのアップロードには非常に多くの用途があります。
1. FormData
前回の記事でフォームを整理する方法としてjqueryのserializeArray関数を使うと書きましたが、この方法はinput[type="file"]に対して無効であり、フォームの内容を統合することができません。関連する問題については、jquery の公式問題を参照してください: https://bugs.jquery.com/ticket/2656。 説明は次のとおりです:
serialize メソッドはファイルの内容を取得できないため、ファイル フォーム フィールドをシリアル化する必要がある理由がわかりません。取得するには、Ajax ファイル アップロード プラグインの 1 つを使用する必要があります。 the content via AJAX.
それではプラグインを使わずに送信されたフォームを取得することはできるのでしょうか?もちろんです!
1.1. FormDataの役割
これが今回紹介するFormDataです。 FormData の MDN 説明によると:
FormData インターフェイスは、フィールドと値を表すキーと値のペアを構築する簡単な方法を提供し、`XMLHttpRequest.send()` を通じてサーバーに簡単に送信できます。フォームのエンコーディング タイプが `multipart/form-data` に設定されている場合と同じ形式を使用します。
FormData オブジェクトは、`entries()` の代わりに `for...of` を使用して走査できます。 `for (var p of myFormData)` は ` for (var p of myFormData.entries()) `
この説明で、少なくとも 2 つの点を理解できました。
FormData は、通常、input[type="file"] フォームを使用して、マルチパート/フォームデータ エンコーディング タイプのフォームを処理するために使用できます。 ...でチェックスルーできます。 (このオブジェクトはブラウザの console.log を使用して印刷することはできません)
input[type="file"] タイプを使用せずに FormData を使用して送信するのはフォームでは不可能ですか?
FormData を使用して、input[type="file"] がなく、エンコード タイプ x-www-form-urlencoded を使用するフォームを送信するとどうなりますか?
FormData を使用しない場合、input[type="file"] を指定してフォームを送信することはできませんか?
はい、この時点のエンコーディング タイプは multipart/form-data です。つまり、フォーム送信メソッドは大まかに次のようになります:
これがわかります。エンコードタイプによりフォームが一意になります。サーバー側で Express4 以降を使用している場合は、このタイプのリクエストを処理するために追加のミドルウェアをインストールする必要があります。そうしないと、req.body、req.param、および req.query にフォーム データが見つかりません。これらについては後で説明します。では、なぜこの単純なフォームを送信するためにこの方法を使用することをまだ推奨しないのでしょうか (これはほとんどの Web サイトの場合です):
送信したフォームがほんの数文字であることに気づいたはずですが、これらの境界を追加すると、原因 フォーム データが大きくなったため、最も効率的なバイナリ エンコードでも、フォーム データを MIME ヘッダーに直接書き込むよりも時間がかかります。
ヒント: ただし、x-www-form-urlencoded は、これらの非英数字文字を処理するのに苦労します。これは、ブラウザーがこれらの非英数字文字を %HH に変換するためです。つまり、各非英数字文字は次のように表されます。置換するのに 3 バイト必要ですが、フォームが非常に長い場合には非常に不親切なので、multipart/form-data が登場しました。
その場合、2 番目の質問に答えると、サーバー (express4) に req.body が表示されます。 '"user"rnrnddrn-----WebKitFormBoundary5Kj2oSfHZKrZjYjsrnContent-Disposition: form-data; name="email"rnrnddddrn-----WebKitFormBoundary5Kj2oSfHZKrZjYjs--rn' }
コードをコピーします
ほら、こうすればこうなりますサーバーはそれを解析しますか? ? ?これは私自身に迷惑をかけるだけです。
FormData の haunted を使用しない場合は、純粋な AJAX を使用して送信することもできます。詳細については、https://developer.mozilla.org/en-US/docs/ を参照してください。 Web/API/XMLHttpRequest/XMLHttpRequest の使用#フォームの送信とファイルのアップロード
1.2. 結論
まとめると、input[type="file"] を含むフォームや英数字以外の文字が多く含まれるフォームを使用する場合は、フォームを送信してエンコードする FormData タイプは multipart/form-data である必要があります。大まかに使用される例は次のとおりです:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>testing form group</title> <script type="text/JavaScript" src="http://cdn.bootcss.com/jquery/3.1.0/jquery.min.js"></script> <script type="text/JavaScript"> function onSubmit(){ var myForm = document.getElementById('form'); var formData = new FormData(myForm); for (var p of formData){ console.log(p); } $.ajax({ type: 'POST', url: '/get', data: formData, dataType: 'json', processData: false, contentType: false, success: function(data){console.log(data)}, error: function(jqXHR){console.log(jqXHR)}, }) } </script> </head> <body> <form action="" method="post" name='info' id='form'> <input type="text" name="user" /> <input type="text" name="email" /> <input type="file" name="file" /> <input type="file" name="file1" /> </form> <button type="button" name='submit' onclick="onSubmit()">提交</button> </body> </html>
注
jquery がデータをさらに処理しないように、$.ajax で processData: false および contentType: false を構成しました:
processData (デフォルト: true)
Type: Boolean
デフォルトでは、データによってdata オプションで渡されたものがオブジェクトである場合 (技術的に言えば、文字列でない限り)、デフォルトのコンテンツ タイプ「application/x-www-form-」に一致するように処理され、クエリ文字列に変換されます。 URLコード化されています。」 DOM ツリー情報または変換したくないその他の情報を送信する場合は、false に設定します。
1.3、FormData API
FormData.append(): 既存のキーに新しい値を追加するか、新しいキーを追加します。
FormData.delete(): キーと値のペアを削除します
FormData.entries (): オブジェクト内のキーと値のペアを走査できるように反復子を返します。
FormData.get(): 最初に指定されたキーの値を返します。
FormData.getAll(): 指定されたキーの値を返します。すべての値の配列
FormData.has(): FormData オブジェクトに指定されたキーと値のペアがあるかどうかを判断します
FormData.keys(): すべてのキーと値のペアのキーの反復を許可する反復子を返します
FormData.set(): 既存のキーの値を変更するか、新しいキーと値のペアを追加します
FormData.values(): すべてのキーと値のペアの値を走査できるようにイテレータを返します
2. input[type= "file"] について
このタイプの入力については、言及する必要がある点がいくつかあります。そうでない場合は、次回忘れることになります:
複数のファイルを選択するには、multiple 属性を使用します。一度、accept 属性を使用して、対応する MIME タイプを実行します。
$(element).files は、アップロードされたファイルの名前とアップロードされたファイルの数 (.name と length) を取得します。
ファイルをアップロードする場合、ファイル名またはサフィックスを確認する必要がある場合があります。このとき、xxx-vx.x.{json| の形式を確認する場合は正規表現が役に立ちます。 (bower-v0.1.json など)、使用される正規表現は次のとおりです:
var reg = /^\w+\-v\d+\.{1}\d+\.(json|yaml)$/i; /*Check if the user has not selected uploaded file*/ if ($(Element).val() === ''){ finalRes.delete('file'); } else { var fileCount = $(Element)[0].files.length; for (var i = 0; i < fileCount; i++) { if (reg.test($(Element)[0].files[i].name )){ console.log('match'); }else{ alert('上传的文件名格式不正确'); return; } } }
その後、サフィックスを削除するときに、 replace(/.(json|yaml)$/, '' ) を使用してサフィックスを削除できます。 。 4. フォームをクリアするための優れた関数は次のとおりです:
function clearAllFields(){ $(':input','#project-info') .not(':button, :submit, :reset, :hidden') .val('') .removeAttr('checked') .removeAttr('selected'); }
$(element) はアップロードしたファイルの入力タグを表すことに注意してください。
finalRes は、新しい FormData
3 の Express サーバー側処理
Express4 のインストール後のフォーム値です。このようなパッケージはたくさんありますが、私は multiparty ミドルウェアを使用することにしました。具体的な利用方法については公式サイト https://github.com/expressjs/node-multiparty をご参照ください。
このミドルウェアを使用するには 2 つの方法があります:
イベント監視を使用する
コールバックを使用する
プロジェクトでコールバックを使用しました:
router.post('/get', function(req, res, next) { var form = new multiparty.Form(); form.parse(req, function(err, fields, files) { if (fields === undefined || files === undefined){ console.log('client send empty data in posting new project'); return res.status(200).json({err:"请求数据为空,请重新提交", status:'failure'}); } console.log(fields, files); console.log('Upload completed!'); }); });
フィールドとファイル内 フィールドは名前に従って編成されています最初のセクションのフロントエンド コードを例として挙げると、この時点での結果は次のようになります:
{ user: [ 'test' ], email: [ 'test1' ] } { file: [ { fieldName: 'file', originalFilename: 'test.html', path: '/home/private/test/QForTTWBipWSPSTpKsUGlRHE.html', headers: [Object], size: 876 } ], file1: [ { fieldName: 'file1', originalFilename: 'test1.html', path: '/home/private/test/aT5T2B_pkkxEVv5OUzjjCxIB.html', headers: [Object], size: 558 } ] }
に従って、デフォルト ファイルはデフォルト ファイル フォルダーにアップロードされています。公式サイトの説明によると、初期化時にuploadDirが設定されていない場合は、システムのos.tmpdir()にアップロードされます。
イベントタイプの実装についても、公式Webサイトで提供されているデモを参照できます。