React FC에서 이미지 파일을 Content-type : multipart/form-data로 POST하는 방법 (axios)

기회로 POST 할 때,
『Content-type: form-data』로 송신할 기회가 있었으므로, 정리합니다.
버튼 부분은 머티리얼 UI를 사용하고 있습니다.

환경



react 16.12.0
typescript 3.7.3
material-ui/core 4.8.0(Button에 사용)

하고 싶은 것



input에서 선택한 파일을 state로 설정, 설정된 파일을 POST

전체



const IconUpload: FC = () => {

  const [userIconFormData, setUserIconFormData] = useState<File>()

  const handleSetImage = (e: ChangeEvent<HTMLInputElement>) => {
    if (!e.target.files) return
    const iconFile:File = e.target.files[0]
    setUserIconFormData(iconFile)
  }

  const handleSubmitProfileIcon = () => {
    const iconPram = new FormData()
    if (!userIconFormData) return

    iconPram.append('user[icon]', userIconFormData)
    axios
      .post(
        'https://api/update',
        iconPram,
        {
          headers: {
            'content-type': 'multipart/form-data',
          },
        }
      )
  }

  return (          
     <form>
       <p>アイコンアップロード</p>
       <input
         type="file"
         accept="image/*,.png,.jpg,.jpeg,.gif"
         onChange={(e: ChangeEvent<HTMLInputElement>) => handleSetImage(e)}
       />
       <Button
         text="変更する"
         variant="contained"
         color="primary"
         type="button"
         onClick={handleSubmitProfileIcon}
         disabled={userIconPreview === undefined}
       />
    </form>
  )
}

export default IconUpload

잘라서 해설



form 주위, 버튼 부분


  <form>
       <p>アイコンアップロード</p>
       <input
         type="file"
         accept="image/*,.png,.jpg,.jpeg,.gif"
         onChange={(e: ChangeEvent<HTMLInputElement>) => handleSetImage(e)}
       />
       <Button
         text="変更する"
         variant="contained"
         color="primary"
         type="button"
         onClick={handleSubmitProfileIcon}
         disabled={userIconPreview === undefined}
       />
    </form>

입력


  • type : file로 설정하면 업로드가 가능합니다
  • accept : 업로드 화면에서 여기에 지정된 확장자의 파일 만 선택할 수 있습니다
  • onChange : 일반적인 input과 달리, value에는 File을 넣을 수 없기 때문에 다른 장소에 취득한 File을 보관 유지하는 function을 호출한다

  • 버튼


  • onClick : onChange로 설정된 state를 axios로 POST하는 함수를 호출합니다.

    파일 가져오기function


    const handleSetImage = (e: ChangeEvent<HTMLInputElement>) => {
      if (!e.target.files) return
      const iconFile:File = e.target.files[0]
      setUserIconFormData(iconFile)
    }
    
    if (!e.target.files) returnTypeScript에서는 undefind가 될 가능성이있는 값에 관해서는 에러가 나오므로 먼저 없는 경우는 return 하는 것을 명시적으로 하고 있다
    const iconFile:File = e.target.files[0]이것이 파일 본체.
    files는 복수 선택 가능한 경우를 갖추어 배열이 되어 있어 [0]으로서 주지 않으면 취득할 수 없다.
    형식은 File.
    setUserIconFormData(iconFile)state에 세트

    그건 그렇고, e.target.files [0]을 URL로 만들고 img에 넣고 싶다면


    const blobUrl = URL.createObjectURL(iconFile)
    
    blob:http://パス 로 변환되어 URL을 다음으로 처리할 수 있습니다.

    파일을 axios로 POST하는 기능


    const createProfileIcon = () => {
        const iconPram = new FormData()
        if (!userIconFormData) return
    
        iconPram.append('user[icon]', userIconFormData)
        axios
          .post(
            'https://api/update',
            iconPram,
            {
              headers: {
                'content-type': 'multipart/form-data',
              },
            }
          )
      }
    

    마침내 API 전송 부분content-type: multipart/form-data

    1. FormData 라는 형식으로 보내주어야 한다.


    const iconPram = new FormData()FormData 개체 만들기
    형은 그만까지 FormDataiconPram.append('user[icon]', userIconFormData)만든 FormData 개체에 매개 변수 추가
    append (키, 전송할 파일)

    2. headers에 'content-type': 'multipart/form-data' 지정



    기본 API 통신할 때는 json이 많을까 생각합니다만, json에서는 올바르게 보내지 못하고, 비어지므로 주의
    _axios.create
    className.defaults.headers = { 'Content-Type': 'multipart/form-data' }
    

    그래서 덮어 씁시다.

    송신 내용





    이런 느낌입니다.

    확인 포인트



  • RequestHeaders의 content-typemultipart/form-data입니다.
  • FormData의 값이 (binary) 입니다

  • 요약



    이제 성공적으로 multipart/form-data로 파일을 POST할 수 있습니다!
    WEB 서비스를 작성할 때, 이미지의 업로드는 잘 나오는 상황이라고 생각하기 때문에, 참고가 되면 다행입니다

    처음으로 이 기능을 구현할 때는 헤매는 부분이 많이 있어, 파일의 POST하는 형태도 몇종인가 있다고 생각하고 있었습니다만, 2종류만 같습니다.
  • File 그대로 송신(multipart/form-data)
  • Base64로 인코딩하여 전송 (application/json)

  • 인코딩하면 json 그대로 보낼 수 있는 이점이 있습니다만, 파일 사이즈가 20~30% 오른다고 합니다.
    하면 할수록 깊고 정답이 없어 헤매지만 즐겁습니다.

    좋은 웹페이지 즐겨찾기