티스토리 뷰


  1   파일업로드시 Ext JS 프로세스



 Ext JS에서 파일업로드를 구현하던중 알지못하는 애러가 계속 터졌다.  분명 서버에서 제대로된 JSON Response를 리턴했는데 계속 잘못된 JSON String이라며 디코딩할 수 없다는 요상한 결과가 떨어졌다.


 처음에는 서버에서 리턴하는 Map 데이터가 스프링의 JacksonMassageConverter를 거쳐 JSON 형식으로 변환해주는 것이 뭔가 잘못되었나 싶어 로직처리후 리턴되는 결과를 JSON 형식의 String으로 리턴을 해보았다. 그 결과 정상적으로 동작하는 것을보고 스프링의 메시지 컨버터가 이상한거였구나 하고 넘겼는데.. API를 살펴보고 여러 테스트를 한 결과 내 손톱만한 지식이 잘못된거라는 알게됬다.


우선 API의 내용은 이러하다.


Returns true if the form contains a file upload field. This is used to determine the method for submitting the form: File uploads are not performed using normal 'Ajax' techniques, that is they are not performed using XMLHttpRequests. Instead a hidden <form> element containing all the fields is created temporarily and submitted with its target set to refer to a dynamically generated, hidden <iframe> which is inserted into the document but removed after the return data has been gathered.

The server response is parsed by the browser to create the document for the IFRAME. If the server is using JSON to send the return object, then theContent-Type header should be set to "text/plain" in order to tell the browser to insert the text unchanged into a '<pre>' element in the document body from which it can be retrieved.

If the Content-Type header is sent as the default, "text/html", then characters which are significant to an HTML parser must be sent as HTML entities, so encode "<" as "&lt;""&" as "&amp;" etc.

The response text is retrieved from the document, and a fake XMLHttpRequest object is created containing a responseText property in order to conform to the requirements of event handlers and callbacks.

Be aware that file upload packets are sent with the content type multipart/form and some server technologies (notably JEE) may require some custom processing in order to retrieve parameter names and parameter values from the packet content.

부족한 영어실력으로 뜻만 대충 해석해보면..


" Submit할때 Form안에 File필드가 존재할경우 true를 리턴합니다. 이것은 Form을 Submit하는 방법을 결정하는데 사용합니다. : 

 파일 업로드는 일반적인 Ajax 기술을 사용하지 않습니다.  즉 XMLHttpRequest를 사용하지 않는다는 것입니다. 대신에 모든 필드를 포함한  hidden form을 일시적으로 생성하고 submit 할때 동적으로 생성한 form을 제출하게 됩니다. 이때 hiden IFRAME을 생성하여 document에 삽입하게 되지만 리턴 된 데이터가 모두 수집된 후에는 다시 지워지게 됩니다."



 첫번째 문단을 해석해보니 왜 크롬 개발자 도구에서 submit 요청이 보이지 않았는지 알 수 있었다. 나는 개발자도구의 네트워크탭에서 XHR만 주구장창 보고있었는데... 당연히 XHR을 사용하지 않으니 XHR탭에는 아무런 내용도 찍히지 않는것이었다. 처음부터 ALL 탭으로 놓고 봤으면 이것도 삽질하지 않았을텐데....



" 서버에서 리턴된 데이터는 IFRAME document를 생성하기 위해 브라우저에 의하여 파싱됩니다. 만약 서버에서 JSON 오브젝트를 리턴하였을 경우 document body 내부의 <pre>태그 안에 삽입되는 데이터가 바뀌지 않도록  Response의 Content-Type은 text/plain이 되어야 합니다. "


 여기서부터 잘못된 점을 찾을 수 있다. 나는 분명 서버에서 Map을 리턴하였고 JacksonMassageConverter에 의해 JSON형식으로 변환이 되었을 것이다. 그런데 중요한점은 JacksonMassageConverter에 의해 리턴된 데이터의 컨텐츠 타입은 application/json 이라는 것이다. 그렇기 때문에 text/plain로 인식하고있는 브라우저에게 application/json을 던져줬으니 이 JSON 데이터가 <pre>태그로 감싸지게 되고 Ext JS의 decode메소드는 오류를 내뱉게 되는것이었다.


 그런데 서버에서 String 형식의 JSON 데이터를 리턴했을때는 아무런 문제가 되지 않았었다. 그것도 이제 알수 있다. 이유는 String을 리턴할 경우 이것을 캐치하는 MessageConverter는 HttpStringMessageConverter라는 것이다. 이 컨버터는 리턴된 데이터의 컨텐츠타입을 text/plain으로 세팅하기때문에 애러가 발생하지 않았던 것이다. 이걸가지고 나는 ..String과 Map의 차이라고 생각하고 있었다.


다음 세 문단은 그냥 알아두면 좋은 내용을 써놓은것 같다. 


 결론은 스프링과 Ext JS를 같이 사용할때 만약 파일 업로드를 할 경우가 생겼다면 반드시 컨텐츠 타입을 신경 써주어야 한다는 것이다. 다음에는 이런 삽질하지 않도록 잊어먹지 않기위해 포스팅한다.

댓글