프로젝트 시 Multipart로 파일과 JSON데이터를 업로드 해야하는 요구사항이 있어 제작한 모듈을 정리한다.
API 모듈 파일
export function requestMultipartJsonObject (requestObj) { // _.merge - Lodash 라이브러리 let reqHeaders = store.state.api.common // 공통적으로 사용하는 헤더정보 _.merge(reqHeaders, requestObj.headers) // 요청 시 설정한 헤더 override _.merge(reqHeaders, { 'enctype': 'multipart/form-data' }) // 헤더에 multipart 추가 const formData = new FormData() // data JsonObject 처리 formData.append('jsonData', JSON.stringify(requestObj.data)) // files 처리 // requestObj.files - (file type)HTMLInputElement 배열 if (requestObj.files) { requestObj.files .filter((file) => file.name && file.file) // 파일선택되지 않은 Input Element제외 .forEach((file) => formData.append(file.name, file.file)) } return axios({ url: requestObj.url, headers: reqHeaders, method: 'post', data: formData }).then(res => { requestObj.callback(res.data) }).catch(res => { // status 200이 아닌경우에도 응답값을 전달 (각 프로젝트에 맞게 수정필요) requestObj.callback(res.response.data) }) }
유틸파일
/** * input(File) Element배열을 requestApi 에서 사용하는 형식으로 반환 * @param {Array of Input File Element} fileArray */ function getRequestFileArray (fileArray) { let reqFileArray = [] verifyFileArray(fileArray) .map((fileObj) => { return fileObj.files }) .filter((fileList) => { return fileList.length > 0 }) .forEach((fileList) => { Array.from(fileList).forEach((file) => { reqFileArray.push({ name: file.name, file: file }) }) }) return reqFileArray } /** * verify Array of Input File Element * @param {Array of Input File Element} fileArray */ function verifyFileArray (fileArray) { if (fileArray instanceof Array) { fileArray.filter((fileObj) => { if (fileObj.files instanceof FileList === false) { console.error('fileObj is not FileList', fileObj) } return fileObj.files instanceof FileList }) return fileArray } else { console.error('fileArray object is not Array', fileArray) return [] } }
1004lucifer
사용파일 (vue)
requestMultipartJsonObject({ url: this.fileUploadUrl, // required headers: { // required 'CUSTOM-HEADER': 'custom-value' // required }, callback: (data) => { // required console.log('data: ', data) this.$refs.resData3.innerHTML = JSON.stringify(data) }, data: { // optional (전달할 JSON 데이터) 'dummyKey': 'dummyValue' }, // optional // 해당 input(file) Element 에 파일이 선택되지 않으면 // 알아서 거르고 선택된 파일만 올라간다. files: getRequestFileArray([ this.$refs.file1, // <input ref="file1" type="file" /> this.$refs.file2 ]) })
Fiddler를 이용해 위의 모듈을 사용해 JSON데이터와 파일2개를 업로드하면 아래와 같이 패킷이 서버로 전송된다.
1004lucifer
POST http://localhost:8080/UploadFile HTTP/1.1 Host: localhost:8080 Connection: keep-alive Content-Length: 3761 Origin: http://localhost:8080 enctype: multipart/form-data User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36 Content-Type: multipart/form-data; boundary=----WebKitFormBoundarydM2WhcM1tdaZ1o1n Accept: application/json, text/plain, */* Referer: http://localhost:8080/ Accept-Encoding: gzip, deflate, br Accept-Language: ko,ja;q=0.9,ko-KR;q=0.8,en-US;q=0.7,en;q=0.6 ------WebKitFormBoundarydM2WhcM1tdaZ1o1n Content-Disposition: form-data; name="jsonData" {"dummyKey":"dummyValue"} ------WebKitFormBoundarydM2WhcM1tdaZ1o1n Content-Disposition: form-data; name="form-check-sign.png"; filename="form-check-sign.png" Content-Type: image/png PNG IHDR o pHYs iTXtXML:com.adobe.xmp <?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c145 79.163499, 2018/08/13-16:40:22 "> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#" xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#" xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/" xmp:CreatorTool="Adobe Photoshop CS6 (Windows)" xmp:CreateDate="2019-04-02T00:24:40+09:00" xmp:ModifyDate="2019-04-08T22:38:07+09:00" xmp:MetadataDate="2019-04-08T22:38:07+09:00" dc:format="image/png" xmpMM:InstanceID="xmp.iid:4c6454d0-90a7-0243-96fc-139a0d4e5ee2" xmpMM:DocumentID="xmp.did:53D94762549211E99E16AF5DA6F340C4" xmpMM:OriginalDocumentID="xmp.did:53D94762549211E99E16AF5DA6F340C4" photoshop:ColorMode="3" photoshop:ICCProfile="sRGB IEC61966-2.1"> <xmpMM:DerivedFrom stRef:instanceID="xmp.iid:53D9475F549211E99E16AF5DA6F340C4" stRef:documentID="xmp.did:53D94760549211E99E16AF5DA6F340C4"/> <xmpMM:History> <rdf:Seq> <rdf:li stEvt:action="saved" stEvt:instanceID="xmp.iid:4c6454d0-90a7-0243-96fc-139a0d4e5ee2" stEvt:when="2019-04-08T22:38:07+09:00" stEvt:softwareAgent="Adobe Photoshop CC 2019 (Windows)" stEvt:changed="/"/> </rdf:Seq> </xmpMM:History> </rdf:Description> </rdf:RDF> </x:xmpmeta> <?xpacket end="r"?> H IDAT( 1j a E ρ E rB T I n - Ig;i aa ) a <8 { $ g % ԴIvI6I o8 K ? Vx ' ) H ԃN] x 7 x 5 %MϜ L% E Bc`鼼 k Y IEND B` ------WebKitFormBoundarydM2WhcM1tdaZ1o1n Content-Disposition: form-data; name="ico_cal.png"; filename="ico_cal.png" Content-Type: image/png PNG IHDR | 0 tEXtSoftware Adobe ImageReadyq e< iTXtXML:com.adobe.xmp <?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.3-c011 66.145661, 2012/02/06-14:56:27 "> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#" xmp:CreatorTool="Adobe Photoshop CS6 (Windows)" xmp:CreateDate="2019-03-26T00:03:45+09:00" xmp:ModifyDate="2019-03-26T00:04:09-15:00" xmp:MetadataDate="2019-03-26T00:04:09-15:00" dc:format="image/png" xmpMM:InstanceID="xmp.iid:3DFC6C7A4F0F11E9B6248EFAA5EFA407" xmpMM:DocumentID="xmp.did:3DFC6C7B4F0F11E9B6248EFAA5EFA407"> <xmpMM:DerivedFrom stRef:instanceID="xmp.iid:3DFC6C784F0F11E9B6248EFAA5EFA407" stRef:documentID="xmp.did:3DFC6C794F0F11E9B6248EFAA5EFA407"/> </rdf:Description> </rdf:RDF> </x:xmpmeta> <?xpacket end="r"?> L IDATxڴ =H Q ) AT 4 D a m YԐ[ D-- LA RcCCA { PM AI s 0?)= p { s< 2 [{ nV L #w w )rg XK aܸ n ]xs k / %\ Q(5 $ b [ [ ~cEs 9 e| ( n <n v {uټ}\ Xߗ+=vt W @ WPV Q 3r Y )de Ԓq i lH+n ^ؐ4z q? 5e q n7OnR T I 7 W < > %vm 5k X y 2 - Nh_㚒 ~ ['& D E Vx!b j Պ jo==. P K UN@T \ -] ;V C' [O W G \: e> } < IEND B` ------WebKitFormBoundarydM2WhcM1tdaZ1o1n--
댓글
댓글 쓰기