본문 바로가기

카테고리 없음

server로 file 전송 과정

깔끔하게 정리하고 싶었는데.. 너무 헤매어 난잡한 글이되었습니다ㅠㅠ

 

 

 

 

게시글에서 사진을 서버로 업로드이전 전송 먼저하려 하였다.

 

평소에는 form태그의 enctype속성을 multipart/form-data로 설정해준뒤

action에 경로만 맞추어 전송만 해주면

controller에서 해당 데이터를 인자로받아 사용할수 있었고

현재 사이트도 위와같은 구조로 진행하려 하였다.

 

다만 다른점이 action경로로 바로 보내는것이 아니라

ajax요청에 설정된 url경로로 data를 실어 보내는 것이었고

data전송이 제대로 되지 않았었다.

 

처음에는 "ajax file 전송" 이라는 키워드로 검색후

인용한 ajax의 코드를 입력했다

그형태는 아래와 같았다.

 

$('.폼태그 버튼 클래스명').on("click",function(){
			
            //var formData = $(".폼태그 클래스명").serialize();
            //file이 아닌경우 원래는 위와 같은방식으로 
            //formData를 ajax의 data로 설정하였다
            
            
			var form = $(".폼태그 클래스명")[0]; 
			var formData = new FormData(form);
			
			$.ajax({
                type: "post",
                enctype: "multipart/form-data", // 이해못하고 사용
                url: "http://localhost:8080/boardRegist",
                data: formData,
                dataType: 'text',
                contentType : false, // 이해못하고 사용
                processData :  false, // 이해 못하고 사용
                success: function (data) {
                    alert("success");
                    console.log(data);
                },
                error: function (request, status, error) {
                    console.log("code:"+request.status+"\n"+"message:"+request.responseText+"\n"+"error:"+error);

                }
            });
		});

 

주석에서 볼수 있듯이 3가지 주석을 잘이해하지 못한상태로 썼는데

api 쪽에서는 자꾸 null값을 전달받는 결과가 발생하였다.

 

이 문제를 해결하려고 시도하는 과정에서 생각보다 많은시간을 사용하게 됐는데

HTTP프로토콜에 관련된 지식이 부족해 쉽게 해결하지 못한다는 생각이 들기시작하여

조금이라도 개념을 얻어가고자 글을 적기 시작했다.

 

data에 FormData를 사용한 이유?

form의 값을 간편하게 전달하기위해 사용한다.

 

FormData란?

form의 키/값들의 집합을 쉽게 구성할수 있도록 도와주는 객체이다.

이를 XHR에 data로 보냈을때 form과 같은 효과를 준다

 

XHR이란?

XMLHttpRequest는 브라우저와 웹 서버간의

메소드가 데이터를 전송하는 객체 폼의  API다.

브라우저의 자바스립트 환경에 의해 제공된다.

( 웹서버간에 데이터를 보낼때 사용하는 객체 정도라고 이해하면 편하다 )

 

proecssData 옵션이란?

말그대로 data에 적용된값을 어떠한식으로 가공해서 보낼것인지 정하는것이다.

default 값으로 query/String으로 전달된다

( url에 "uri?파라미터=값" 형태로 전달되는 것과 같다)

 

processData의 옵션에 false를 준이유?

정답부터 말하자면 file객체를 전송하기 위해서이다.

 

같은 FormData인데 왜 file을 전송할때는 안하던 processData를 설정해줘야 하는걸까?

url로 보내는 query String의경우 file의 데이터자체를 보낼수없지만

단순히 키,벨류 형태로만 보낼때는 FormData도 query Stirng으로 보내도

전달받아 사용하는데 문제가 없다고 결론지었다.

 

querey String?이란

url의 파라미터값이라고 부르는것이 query String이었다. 

좋은 사진을 찾아서 첨부하겠다.

 

contentType은 ?

응답 header안의 content-type객체로 media tpye을 포함하고 있다

 

contentType 의 옵션이 false인 이유?

ajax요청시 content-tpye의 기본값은 application/x-www-form-urlencoded 인데
file의경우 기본값으로는 전송이 안되서 false를 넣는다고 생각한다

multipart/form-data로 바꿔주기 위해서라고 설명하기에는

직접 contentType에 multipart/form-dat를 입력하면 에러가난다.

 

application/x-www-form-urlencoded 란?

&로 분리되고 "="기호로 값과 키를 연결하는

key-value tuple로 인코딩 되는 값이다. 라고되어있고

"percent encoded"로 인코딩 된다라는 설명과 함께

"바이너리 데이터에 사용하기 위해 적절하지 않습니다"

(바이너리 데이터는 use multipart/form-data) 를 사용해 주라고 되어있는데

내가 올리는 이미지 파일들은 전부 바이너리 데이터형태로 전송이 된다.

떄문에 contentType을 변경해주는 것은 적절하다고 생각되었지만

어째서 multipart/form-data가아닌 fasle를 지정해주는지 모르겠다

multipart/form-data로 content-type이 변경되는 것은 확실한 것같다.

 

그럼에도 불구하고 요청이 잘가지 않아서

개발자도구의 NetWork의 헤더객체를 확인하기 시작했다

 

보면 일반 헤더에서  405 오류가 발생을 했는데

POST로 의 요청이 서버를 잘찾아갔으나 서버에서

해당 요청을 허용하지 않았다는 것이다

이유는 여러가지가 있을텐데 리퍼러정책에 쓰여있는

리퍼러정책을 보면 strinct-origin-when-cross-origin이 사실 405에러의 주된이유중 하나이다

하지만 controller쪽에서 origin에대한 모든경로를 허용시킨상태였고

get요청을 보냈을경우 발생하지 않기에

POST요청에 대한 문제라고 생각이 들었다

 

 

이후 strinct-origin-when-cross-origin 405에러의 원인이

서버의 허용 uri뿐만아니라 HTTP 메서드 종류등 이외의 것들이 있을수 있다는 것을 알았다.

 

 

보면 분명 Controller의 전역 어노테이션은  @PostMapping인데

응답헤더의 Allow는 GET으로 되어있다

이말은 즉 해당 uri요청은 HTTP GET 타입만 허용한다는 것이다.

그래서 Allow: GET을 변경하려고 계속 구글링을 했었다.

 

여기서 Allow :GET 이라는 문구에 꽃혀서 2틀동안 구글링만 했었다 정말.

 

그런데 도움을 구하던중 요청헤더의 HOST: 의 ip와 port값이 요청한 앱의

uri와 동일하다는것을 알게도었다.

그러니까 클라이언트의 요청이 계속 클라이언트로 가고있다는것이었다..

 

원인은 form태그였다.

하나의 project안에서 웹을 구축할때는 form태그를 통해 데이터를 전송했었다.

현재는 form태그의 button이 눌릴때 input값의 데이터를 FormData객체에 담고

ajax 요청에 실어 보내는 형태를 사용했었다.

 

그래서 form버튼을 누르면 form태그의 상대경로 요청과

ajax의 절대경로 요청이 동시에 작용하였고 

나는 form태그의 오류를 ajax요청시 생기는 오류라고 생각하고

원인을 찾아내려고 했던것이 엄청난 삽질을 하게된 원인이 되었던것이다.

정말 생각치도 못했었다

 

결국 form태그를 지우고나서야 요청헤더의 Host값이 정상출력되었고

ajax의 contentType 과

jackson-corm 라이브러리와 CommonsMuptiviewResolver를 추가하여 해결이 되었다.