개인 프로젝트 진행 중 404 에러에 막혀 3일간을 삽질이 시작되었다..
호출 url이 정확한지, 메소드 타입은 이상이 없는지 패키지 스캔 경로가 정확한지 Tomcat - server.xml의 path 경로는 어떻게 되어있는지 확인해봤지만 이상이 없었고 도저히 찾지 못해서 오키에 질문을 남겼다.
코드는 아래와 같이 저장 이벤트가 발생하면 ajax를 실행하고 컨트롤러에서 이벤트를 처리하는 구조이다.
addEvent.jsp
// 새로운 일정 저장
$.ajax({
type: "POST",
url: "/schedule/addSchedule.do",
cache: false,
dataType: "json",
data: JSON.stringify(eventData),
contentType: "application/json; charset=utf-8",
success: function(data) {
if(data.result == "OK"){
alert("일정이 등록되었습니다.");
// 모달 입력창 초기화
$("#dayEventModal").find("input, textarea").val("");
$("#dayEventModal").find("input:checkbox").prop("checked", false);
$("#dayType option:eq(0)").prop("selected", true);
$("#dayCdcmp option:eq(0)").prop("selected", true);
$("#dayColor option:eq(0)").prop("selected", true);
//location.reload();
}
},
error : function(request, status, error) {
alert("code : " + request.status + "\n" + "message : " + request.responseText + "\n" + "error : " + error);
}
});
addSchedule.java
/** 스케줄 입력 */
@RequestMapping(value= "/schedule/addSchedule.do", method = {RequestMethod.GET, RequestMethod.POST})
public @ResponseBody String addSchedule(HttpSession session, @RequestBody String filterJSON, HttpServletRequest request) {
ScheduleVO scheduleVO = new ScheduleVO();
LoginVO loginVO = (LoginVO) session.getAttribute("loginVO");
JSONObject result = new JSONObject();
JSONObject json = (JSONObject) JSONValue.parse(filterJSON);
System.out.println("filterJSON : " + filterJSON);
try {
String schno = String.valueOf(json.get("schno"));
String userid = loginVO.getUserid();
String title = String.valueOf(json.get("title"));
String content = String.valueOf(json.get("content"));
String type = String.valueOf(json.get("schtype"));
String startdt = String.valueOf(json.get("startdt"));
String enddt = String.valueOf(json.get("enddt"));
String bgcolor = String.valueOf(json.get("bgcolor"));
String txtcolor = String.valueOf(json.get("txtcolor"));
String allday = String.valueOf(json.get("allday"));
scheduleVO.setSchno(schno);
scheduleVO.setUserid(userid);
scheduleVO.setTitle(title);
scheduleVO.setContent(content);
scheduleVO.setSchtype(type);
scheduleVO.setStartdt(startdt);
scheduleVO.setEnddt(enddt);
scheduleVO.setBgcolor(bgcolor);
scheduleVO.setTxtcolor(txtcolor);
scheduleVO.setAllday(allday);
scheduleService.addSchedule(scheduleVO);
result.put("result", "OK");
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
result.put("result", "ERROR");
}
return result.toJSONString();
}
오키에서 받은 답변은 csrf 토큰이었다.
사실 시큐리티 설정에서 csrf 설정을 해주지 않았기 때문에 당연히 상관없을 줄 알았다.
그런데 구글링 중 시큐리티 4버전 이상부터는 csrf가 기본 적용되어서 post 방식으로 데이터를 넘길 때 반드시 필요한 것이었다. 여기서 또 의문은 그럴 때 에러는 403 에러로 알고 있는데 어째서 404 에러가 나온 것인지였다.
일단 해보기로 했다.
hidden으로 토큰 값을 넣어주고 beforeSend 옵션을 추가해 데이터 전송전 csrf 값을 헤더에 설정했다.
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
var token = $("input[name='_csrf']").val();
var header = "X-CSRF-TOKEN";
// 새로운 일정 저장
$.ajax({
type: "POST",
url: "/schedule/addSchedule.do",
cache: false,
dataType: "json",
data: JSON.stringify(eventData),
contentType: "application/json; charset=utf-8",
beforeSend : function(xhr)
{
xhr.setRequestHeader(header, token);
},
success: function(data) {
if(data.result == "OK"){
alert("일정이 등록되었습니다.");
// 모달 입력창 초기화
$("#dayEventModal").find("input, textarea").val("");
$("#dayEventModal").find("input:checkbox").prop("checked", false);
$("#dayType option:eq(0)").prop("selected", true);
$("#dayCdcmp option:eq(0)").prop("selected", true);
$("#dayColor option:eq(0)").prop("selected", true);
//location.reload();
}
},
error : function(request, status, error) {
alert("code : " + request.status + "\n" + "message : " + request.responseText + "\n" + "error : " + error);
}
});
결과는...
성공이었다.
내 생각이 틀렸던걸까. 404 에러는 csrf와 무관할 것이라고 단정지은 것이 잘못인가보다..
문제가 해결되어 다행이지만 조금은 찝찝한 기분이다.
아무튼 나와 같은 상황을 겪을 누군가에게 참고가 되길 바라며 포스팅을 남겨본다.