Project2021

[javascript] ajax로 form data 보내기

뱅타 2021. 6. 12. 15:11

form_data를 restAPI의 put으로 ajax를 사용해서 값을 보내려고 하는 과정에서 겪은 문제들을 기록하겠습니다.

우선 controller에 post 방식으로 요청을 시도했을 때 multipart/form-data 값을 잘 받아오는지 확인해 보겠습니다.

http

<form class="basic-form profile_image" id="profile_imageForm" name="member" enctype="multipart/form-data" >
	<div class="img-grid-right">
		<label class="d-block"> Profile picture</label>
		<img class="mr-3 rounded-circle" height="200" width="200" id="profile_img"src="${cPath}/resources/profiles/1.jpeg">
		<button type="button" class="btn mb-1 btn-outline-info edit-profile">Edit</button>
		<input class="form-control btn mb-1 btn-outline-info" id="upload_image" type="file" name="files" accept="image/*" hidden="hidden" />
	</div>
</form>

javascript

var imageSelect = $("#upload_image").on("change", function(){
	var formdata = $("#profile_imageForm")[0];
	var form_data = new FormData(formdata);
	$.ajax({
		url : getContextPath()+"/restapi/member/members/member" ,
		type : 'post',
		data : form_data,
		processData: false,
		contentType: false,
		success : function(res) {
			$("#profile_img").attr("src", getContextPath()+"/resources/profiles/"+res.fileName);
			$("#side-bar-profile_img").attr("src", getContextPath()+"/resources/profiles/"+res.fileName);
		},
		error : function(xhr) {
			console.log(xhr);
			if(xhr.status == '404'){
				alert("실패");				
			}else{
				alert("status : " + xhr.status);
			}
		},
		cache : false,
		dataType : 'json'
	})
})

post를 이용해서는 잘 넘어감.

하단의 res를 살펴보면 (wrapping된 값들을 보기 위해 HttpServletRequest를 의도적으로 넣어줌)

StandardMultipart가 제일 마지막에 실행되어서 wrapping param을 내보내는 것을 볼 수 있습니다.

form_data의 files도 잘 받아옵니다.

개발자 도구의 network로 본 body 부분 입니다.

우선 HiddenHttpMethodFilter를 사용해서 post를 put으로 변환시켜 줍니다.

<input type="hidden" value="put" name="_method">

***HiddenHttpMethodFilter??? restAPI의 post, get 이외의 put, delete로 method를 전달하기 위한 filter입니다.

put으로 바꾸는 순간

분명 개발자 도구로 보면 _method param 하나가 추가되었을 뿐입니다만

이렇게 form_data에 값을 제대로 맵핑시켜주지 못합니다.

이렇게 제대로 매핑이 안되는 이유는

하단의 request 트리를 보시면 StandardResolver가 post와는 다르게 작동을 하지 않은 것을 볼 수 있습니다.

multipartFilter가 존재합니다. 먼저 실행시켜 주기 위해서 filter를 적용시켜 줍니다.

안으로 들어가 보면 어떻게 사용하는지 보여줍니다.

이 filter는 자체적으로 사용할 수 없고, bean에 등록되어 있는 multipartResolver를 주입받아서 사용합니다. filter로 등록할 filter-name과 bean에 등록하기 위한 id를 filterMultipartResolver 로 맞춰주어서 사용해야 합니다.

xccEscapeServletFilter와 HiddenHttpMethodFilter가 multipart 부분을 따로 처리해 주지 않고 하나의 String parameter로 wrapping해서 값을 넘기기 때문에 MultipartResolver에 넘어와도 multipart라는 부분이 이미 소거되었기 때문에 wrapping을 제대로 해주지 못합니다.

제대로 적용시키기 위해서는 body에 실린 multipart부분과 다른 parameter들을 먼저 처리해 주어야 합니다.

따라서 다른 wrapping이 작동하기 전에 multipartFilter를 적용시킵니다.

그러니 filter 를 적용시키더라도 multipartFilter를 다른 두 필터 위에 위치시켜 줍니다.

servlet-context.xml(하위 컨테이너)의 디스페쳐 서블릿이 사용하는 이 resolver를 상위 컨터이너로 넘깁니다.(id의 경우 filter가 인식할 수 있는 id로 교체합니다.

하위 컨테이너에 있을 경우 D.S가 제대로 사용하기 위해 id = "multipartResolver"로 주어야 합니다.)

앞으로는 filter에 적용시키기 때문에 D.S가 쓸일이 없어지기 때문에 servlet-context.xml에서 삭제합니다.

root-context.xml

id = filterMultipartResolver

성공 시 결과

728x90
반응형