프로젝트 시 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--
댓글
댓글 쓰기