결론부터 말하자면, 아무리 찾아도 그 어디에도 설명이 없어서 🤯
multipart/form-data로 이미지 데이터를 전송 할 때는 아래와 같은 형태로 formData에 append 해야 한다
는데, 어떤 공식문서에도 명시되어 있지 않고 이 형태를 지켜야 한다는 걸 대체 어디서 알았는지 출처를 밝힌 블로그 포스트도 없었다.
{
uri: image_path,
name: file_name,
type: image_type
}
너무 답답한데!! 궁금한데!! 스프린트 돌려야하니까 내 궁금증은 고이 접어두고 일단 써서 해결할까 했지만, J님이 그러지 말라고 하셨다. 파헤쳐라!하셔서 그렇다면?😏 하고 열심히 파헤치러 갔다.
RN 앱에서 이미지를 서버에 업로드 해야했다. 이미지는 파일이니까 일단 구글링을 해본다.
const data = new FormData();
data.append('my_photo', {
uri: filePath, // your file path string
name: 'my_photo.jpg',
type: 'image/jpg'
}
새로운 formData 오브젝트를 생성한 뒤 필요한 data를 key - value 형태로 append 하면 된다고 한다. 그런데 RN에서 이미지를 업로드 할 때 반드시 uri, name, type 값이 있는 오브젝트를 append 해야 한다.
궁금하니까 찾아 본다.
The
FormData
interface provides a way to construct a set of key/value pairs representing form fields and their values, which can be sent using the fetch() or XMLHttpRequest.send() method.
그런데 데이터를 append
할 때는 name과 value를 파라미터로 전달해야 하고, value 값으로는 string 또는 blob을 쓸 수 있다고 한다.
name
The name of the field whose data is contained in value
.
value
The field's value. This can be a string or Blob
(including subclasses such as File
). If none of these are specified the value is converted to a string.
출처: https://developer.mozilla.org/en-US/docs/Web/API/FormData
궁금하니까 또 찾아 본다.
The
Blob
object represents a blob, which is a file-like object of immutable, raw data; they can be read as text or binary data, or converted into a ReadableStream so its methods can be used for processing the data.Blobs can represent data that isn't necessarily in a JavaScript-native format. The
File
interface is based onBlob
, inheriting blob functionality and expanding it to support files on the user's system.
An iterable object such as an Array, having ArrayBuffers, TypedArrays, DataViews, Blobs, strings, or a mix of any of such elements, that will be put inside the Blob.
new Blob(array)
const array = ['<q id="a"><span id="b">hey!</span></q>']; // an array consisting of a single string
const blob = new Blob(array, { type: "text/html" }); // the blob
Blob은 iterable object 형태라는데, 왜 uri, name, path 값이 있는 오브젝트를 써야 하는지에 대한 답이 되지는 않는다.
출처: https://developer.mozilla.org/en-US/docs/Web/API/Blob
문서를 자세히 다시 읽어보니 File은 Blob의 subclass라니까 이번엔 File을 찾아본다.
MDN File API에서 File Constructor를 읽어보면 new File(bits, name, options)
로 File 오브젝트를 생성할 수 있는데, bits에는 iterable한 오브젝트, 스트링이 들어가고, name에는 파일명 또는 경로, options에는 type과 lastModified를 설정할 수 있다. 오 이제 좀 uri, name, type과 비슷한 걸 찾은 것 같다.
출처: https://developer.mozilla.org/en-US/docs/Web/API/File/File
이미지 URIfmf JS File Object로 바꾸려면 data url을 Unit8Array로 바꿔주고 file name과 type을 지정해주면 된다는 스택오버플로우 글을 찾았다. 좀 더 비슷해진 것 같지만 아직 확신할 수 없다.
출처: https://stackoverflow.com/questions/43358456/convert-image-uri-into-javascript-file-object
I am currently using XHR to upload images with no issues. My implementation is based off of facebook's example https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/XHRExample.ios.js#L183-L230
Something like this:
formdata.append(photo, {type: "image/jpeg", name: ____, uri: ______ });
출처: https://github.com/react-native-image-picker/react-native-image-picker/issues/31
나는 이제 더 이상 못 찾겠다 손 들었을 때 감사하게도 사수님,,, 상사,,, (그러고 보니 밖에서 뭐라고 불러야 할지 잘 모르겠는) J님께서 RN 코드를 직접 파헤쳐서 아래 코드를 찾아주셨다.
결론은 RN이 이렇게 쓰도록 정의해 놓았다는 거다. 많이 허무해 🤯 근데 웃긴 건 코멘트에는 분명 filename과 content type이 ‘optional’이라고 쓰여있지만 안 쓰면 에러난다. PR 날릴까?,,,🤨
출처: https://github.com/facebook/react-native/blob/main/Libraries/Network/FormData.js
// The body part is a "blob", which in React Native just means
// an object with a `uri` attribute. Optionally, it can also
// have a `name` and `type` attribute to specify filename and
// content type (cf. web Blob interface.)
if (typeof value === 'object' && !Array.isArray(value) && value) {
if (typeof value.name === 'string') {
headers['content-disposition'] += '; filename="' + value.name + '"';
}
if (typeof value.type === 'string') {
headers['content-type'] = value.type;
}
return {...value, headers, fieldName: name};
}
// Convert non-object values to strings as per FormData.append() spec
return {string: String(value), headers, fieldName: name};
});
}
}
뭐든 왜 그렇게 써야 하는지 생각해보지 않고, ‘그냥 그렇게 쓰래’ 하고 넘어가지 말자. 궁금한 건 끝까지 파헤치고, 그것도 안 되면 사수를 부여잡고 애원해서라도 (애원하지 않았음) 알아내는 개발자가 되자💪🏼
역시 글쓰기는 어렵다,,,
formData 관련해 더 정확한 정보를 아신다면 댓글로 공유해 주세요🤩