서문
이전 글에서는 폼을 이용하여 앞, 뒤 데이터의 상호작용에 대해 이야기한 적이 있는데, 폼에서 브라우저와 서버 간의 연결에 대해 몇 가지 설명한 것 같습니다. 형식을 마스터했지만 현실은 잔혹합니다. 최근 프로젝트에서 이전 기사에서 방금 클릭한 형식에 대한 많은 지식이 있음을 발견했습니다. 이 컨텐츠는 파일업로드 등 꽤 많은 곳에서 사용됩니다.
1. FormData
이전 글에서 폼을 정리하는 방법은 jquery의 serializeArray 함수를 사용하는 것이라고 언급했는데, 이 방법은 input[type="file"]에는 유효하지 않습니다. 파일의 내용을 양식에 통합할 수 없다고 합니다. 관련 문제는 jquery 공식 이슈(https://bugs.jquery.com/ticket/2656)를 참조하세요. 설명은 다음과 같습니다.
직렬화 메소드는 파일의 내용을 가져올 수 없으므로 파일 양식 필드를 직렬화해야 하는 이유를 이해할 수 없습니다. Ajax 파일 중 하나를 사용해야 합니다. 플러그인을 업로드하면 AJAX를 통해 콘텐츠를 얻을 수 있습니다.
그럼 플러그인을 사용하지 않고도 제출된 양식을 얻을 수 있을까요? 당연하죠!
1.1. FormData의 역할
저희가 소개하고 싶은 FormData입니다. FormData의 MDN 설명에 따르면:
FormData 인터페이스는 필드와 값을 나타내는 키-값 쌍을 작성하는 간단한 방법을 제공하며 `XMLHttpRequest.send를 통해 쉽게 전달될 수 있습니다. ()`가 서버로 전송되었습니다. 양식의 인코딩 유형이 `multipart/form-data`로 설정된 것과 동일한 형식을 사용합니다.
`entries()` 대신 `for...of`를 사용하여 FormData 객체를 탐색할 수 있습니다. `for (var p of myFormData)`는 ` for (var p of myFormData.entries() )`
이 설명을 통해 최소한 두 가지 사항을 이해할 수 있었습니다.
FormData는 multipart/form을 처리하는 데 사용할 수 있습니다. -데이터 인코딩 유형 양식 일반적으로 input[type="file"];
FormData의 필드는...in을 통해 확인할 수 있습니다. (이 개체는 브라우저에서 console.log를 사용하여 인쇄할 수 없습니다.)
그러면 일부 어린이는 분명히 다음과 같이 묻습니다.
사용하지 않습니까? FormData를 사용하여 input[type="file"] 없이 양식을 제출할 수 있습니까?
FormData를 사용하여 input[type="file"] 없이 x-www-form-urlencoded 인코딩 유형으로 양식을 제출하는 경우 어떻게 되나요?
FormData를 사용하지 않는 경우 input[type="file"]로 양식을 제출할 수 없나요?
그런 다음 데모를 사용하여 이 두 가지 문제를 설명합니다.
네, 현재 인코딩 유형은 양식 제출 방법인 multipart/form-data입니다. 대략 다음과 같습니다.
이 인코딩 유형 형식이 다르다는 것을 알 수 있습니다. 서버 측에서 express4 이상을 사용하는 경우 이러한 유형의 요청을 처리하기 위해 추가 미들웨어를 설치해야 합니다. 그렇지 않으면 req.body, req.param 및 req.query에서 양식 데이터를 찾을 수 없습니다. 이에 대해서는 나중에 논의하겠습니다. 그렇다면 우리는 여전히 이 방법을 사용하여 간단한 양식을 제출하는 것을 옹호하지 않는 이유가 있습니다(대부분의 웹사이트가 이에 해당합니다).
우리가 제출한 양식이 단 몇 글자에 불과하다는 사실을 발견하셨을 것입니다. 이러한 경계로 인해 양식 데이터가 더 커집니다. 즉, 가장 효율적인 바이너리 인코딩이라도 양식 데이터를 MIME 헤더에 직접 쓰는 데 걸리는 시간보다 더 오래 걸립니다.
팁: 그러나 x-www-form-urlencoded는 영숫자가 아닌 문자를 처리하는 데 어려움을 겪습니다. 왜냐하면 브라우저가 영숫자가 아닌 문자를 %HH로 변환하기 때문입니다. 즉, 영숫자가 아닌 모든 문자는 %HH로 변환됩니다. 영숫자 문자는 3바이트로 대체됩니다. 이는 양식이 매우 길면 매우 불리하므로 multipart/form-data가 나타납니다.
두 번째 질문에 대답하려면 서버(express4)에서 req.body를 볼 수 있습니다.
{ '------ -WebKitFormBoundary5Kj2oSfHZKrZjYjsrnContent -처리: 양식-데이터; 이름': '"사용자"rnrnddrn------WebKitFormBoundary5Kj2oSfHZKrZjYjsrnContent-처리: 양식-데이터; 이름="email"rnrndddrn------WebKitFormBoundary5Kj2oSfHZKrZjYjs- -rn' }
코드 복사
보세요, 서버에 어떻게 파싱을 요청하나요? ? ? 이것은 나 자신에게 문제를 일으키고 있습니다.
FormData의 유령을 사용하지 않는 경우 순수 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>
참고
$.ajax는 jquery가 데이터를 추가로 처리하지 못하도록 processData: false 및 contentType: false로 구성됩니다.
processData( 기본값: true)
유형: 부울
기본적으로 data 옵션을 통해 전달된 데이터가 객체인 경우(기술적으로 말하면 문자열이 아닌 한) 처리되어 기본 콘텐츠 유형 "application/x-www-form-urlencoded"와 일치하도록 쿼리 문자열로 변환됩니다. 변환하고 싶지 않은 DOM 트리 정보나 기타 정보를 보내려면 false로 설정하세요.
1.3, FormData API
FormData.append(): 기존 키에 새 값을 추가하거나 새 키를 추가합니다.
FormData.delete(): 키-값 쌍 삭제
FormData.entries(): 개체
FormData에서 키-값 쌍을 순회할 수 있도록 반복자를 반환합니다. (): 주어진 키의 첫 번째 값을 반환
FormData.getAll(): 주어진 키의 모든 값의 배열을 반환
FormData.has(): FormData 객체는 지정된 키-값 쌍을 사용합니다.
FormData.keys(): 모든 키-값 쌍의 키 반복을 허용하는 반복자를 반환합니다.
FormData.set(): 수정합니다. 기존 키 또는 새 키-값 쌍 추가
FormData.values(): 모든 키-값 쌍의 값을 순회할 수 있도록 반복자를 반환합니다
2. input[type="file"]
이러한 유형의 입력에 대해 언급해야 할 몇 가지 사항이 있습니다. 그렇지 않으면 다음에 잊어버릴 것입니다:
여러 속성 사용은 한 번에 여러 파일을 선택할 수 있으며, 수락 속성을 사용하여 해당 MIME 유형을 실행합니다.
$(element).files는 업로드된 파일의 이름과 업로드된 파일 수(.name 및 길이)를 가져올 수 있습니다.
파일을 업로드할 때 파일 이름이나 접미사를 확인해야 하는 경우가 있는데 이때 xxx - 형식을 확인하면 정규식이 유용합니다. vx.x.{json|yaml}(예: 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; } } }
그런 다음 접미사를 제거하면 바꾸기를 사용할 수 있습니다. (/.(json|yaml)$/, '') 접미사를 제거합니다. 4. 양식을 지우는 좋은 기능은 다음과 같습니다.
function clearAllFields(){ $(':input','#project-info') .not(':button, :submit, :reset, :hidden') .val('') .removeAttr('checked') .removeAttr('selected'); }
$(element)는 업로드한 파일의 입력 태그를 나타냅니다.
finalRes는 새 FormData 이후의 양식 값입니다.
3. Express 서버 측 처리
Express4.x 이후 이동 미들웨어가 많기 때문에 multipart/form-data 인코딩 유형이 있는 양식을 처리하려면 직접 설치해야 합니다. 그러한 패키지가 많이 있으며 저는 다자간 미들웨어를 사용하기로 결정했습니다. 구체적인 사용 방법은 공식 홈페이지(https://github.com/expressjs/node-multiparty)를 참고하세요.
이 미들웨어를 사용하는 방법에는 두 가지가 있습니다.
이벤트 청취 양식 사용
콜백 양식 사용
프로젝트에서는 콜백 형식을 사용합니다.
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!'); }); });
파일의 필드와 필드는 양식에 제공한 이름에 따라 구성됩니다. 첫 번째 섹션의 end 코드를 입력하면 이때 결과는 다음과 같습니다.
{ 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()에 업로드됩니다.
이벤트 유형 구현도 유사하며, 공식 홈페이지에서 제공되는 데모를 참고하시면 됩니다.