# ajax - POST방식으로 PUT, PATCH, DELETE 사용하기 (HiddenHttpMethodFilter)
프로젝트를 진행하면, 보안상의 이유로 http method 중 GET, POST 만 사용 가능 할 때가 있다.
그렇지만 굳이 굳이 @PutMapping, @PatchMapping, @DeleteMapping 를 사용하고 싶을 때, HiddenHttpMethodFilter를 적용하여 POST방식으로 요청하고 PUT, PATCH, DELETE 메소드를 @RequestParam으로 파라미터로 맵핑!
- GET, POST만 허용하기: https://hjho95.tistory.com/13
# HTTP METHOD 종류
HTTP에서 지원하는 요청 메시지는 다음과 같다.
- GET: 클라이언트가 서버에게 URL에 해당하는 자료의 전송을 요청한다.
- HEAD: GET 요청으로 반환될 데이터 중 헤더 부분에 해당하는 데이터만 요청한다.
- POST: 클라이언트가 서버에서 처리할 수 있는 자료를 보낸다. 예를 들어, 게시판에 글을 쓸 때 클라이언트의 문서가 서버로 전송되어야 한다. 멱등성을 보장하지 않는다.
- PATCH: 클라이언트가 서버에게 지정한 URL의 데이터를 부분적으로 수정할 것을 요청한다.
- PUT: 클라이언트가 서버에게 지정한 URL에 지정한 데이터를 저장할 것을 요청한다.
- DELETE: 클라이언트가 서버에게 지정한 URL의 정보를 제거할 것을 요청한다.
- TRACE: 클라이언트가 서버에게 송신한 요청의 내용을 반환해 줄 것을 요청한다.
- CONNECT: 클라이언트가 특정 종류의 프록시 서버에게 연결을 요청한다.
- OPTIONS: 해당 URL에서 지원하는 요청 메세지의 목록을 요청한다.
이 중 GET 과 HEAD 요청은 원칙적으로 이를 호출한다고 해서 서버 측의 데이터에 변화가 있어서는 안 된다. 이를 Safe Method 라고 분류한다. 또한, GET, HEAD, PUT, DELETE 는 동일한 요청이 한번 전송되었을 때와 여러 번 연속하여 전송되었을 때의 서버 측의 처리 결과가 동일해야 한다. 이를 Idempotent Method 라고 분류한다.
참조: https://namu.wiki/w/HTTP - (5.1) 라고 함.
이슈: https://softwareengineering.stackexchange.com/questions/114156/why-are-there-no-put-and-delete-methods-on-html-forms
조금 더 궁금한 사람들은 찾아보기 바람.
# 환경
/**
* tool: STS 4.13.0
* version: 2.7.3-SNAPSHOT
* java: 1.8
* type: MAVEN
* view: THYMELEAF
* jQuery: 3.6.0
*/
# HiddenHttpMethodFilter
public class CommonMethodFilter extends HiddenHttpMethodFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException
{
if(FilterConfig.isStatic(request.getRequestURI())) {
filterChain.doFilter(request, response);
} else {
super.doFilterInternal(request, response, filterChain);
}
}
}
# Configuration
@Configuration
public class FilterConfig {
public static boolean isStatic(String uri) {
if(uri.startsWith("/js") || uri.startsWith("/css") || uri.startsWith("/images") || uri.startsWith("/favicon.ico")) {
return true;
}
return false;
}
/**
* 이 필터는 POST 본문 매개변수를 확인해야 하는 고유한 필요성 때문에
* 다중 부분 POST 요청의 경우 다중 부분 처리 후에 실행해야 합니다.
* 따라서 일반적으로 이 HiddenHttpMethodFilter 앞에 Spring MultipartFilter를 배치합니다.
* Only POST, Only application/x-www-form-urlencoded; charset=utf-8
*/
@Bean
public FilterRegistrationBean<CommonMethodFilter> methodFilter() {
String[] urlPatterns = new String[] {"/test/send/*"};
CommonMethodFilter commonMethodFilter = new CommonMethodFilter();
commonMethodFilter.setMethodParam("_methodName");
FilterRegistrationBean<CommonMethodFilter> bean = new FilterRegistrationBean<>(commonMethodFilter);
bean.addUrlPatterns(urlPatterns);
bean.setOrder(1);
bean.setEnabled(true);
return bean;
}
}
# view
# html (일부분 발췌)
<h3>PUT, PATCH, DELETE (application/x-www-form-urlencoded)</h3>
<div>
<input type="text" id="requsetsNew" placeholder="Put, Delete Test" style="display: inline;"/>
<br>
<input type="button" onclick="test.requsetsNew('put')" value="PUT" style="display: inline;"/>
<input type="button" onclick="test.requsetsNew('patch')" value="PATCH" style="display: inline;"/>
<input type="button" onclick="test.requsetsNew('delete')" value="DELETE" style="display: inline;"/>
</div>
# ajax send function (일부분 발췌)
const test = {
requsetsNew: function(method) {
const input = {
param1: $('#requsetsNew').val(),
param2: method,
_methodName: method
}
sendRequestNew(`/test/send/${method}`, 'post', input,
function(result) {
console.log(result);
},
);
},
}
function sendRequest(url, method, input, cbSuccess) {
$.ajax({
// options
url : url,
method : (method) ? method : "POST",
data : input,
dataType : "json",
beforeSend : function(jqXHR, settings) {}
// success
}).done(function(output, textStatus, jqXHR) {
cbSuccess(output);
// error
}).fail(function(jqXHR) {
console.log("ERROR");
// complete
}).always(function(output, textStatus, jqXH) {
console.log("COMPLETE");
}
);
}
# @Controller (일부분 발췌)
@Slf4j
@Controller
@RequestMapping("/test/send")
public class TestSendController {
@PutMapping("/put")
public @ResponseBody Map<String, String> put(@RequestParam Map<String, String> input) {
log.debug("[PARAMETER] {}", input);
return input;
}
@PatchMapping("/patch")
public @ResponseBody Map<String, String> patch(@RequestParam Map<String, String> input) {
log.debug("[PARAMETER] {}", input);
return input;
}
@DeleteMapping("/delete")
public @ResponseBody Map<String, String> delete(@RequestParam Map<String, String> input) {
log.debug("[PARAMETER] {}", input);
return input;
}
}
# 내용
HiddenHttpMethodFilter 를 적용하여 @PutMapping, @PatchMapping, @DeleteMapping 을 사용할때에는 몇가지 제약이 있다.
- http method는 POST만 사용할 것.
- contentType은 application/x-www-form-urlencoded 를 사용할 것.
- setMethodParam("_methodName") 이용하여 파라미터명을 변경하면, 해당 변수명으로 메소드 값을 넣어줄 것.
- (default) _method
- POST에서 메소드 변경은 PUT, PATCH, DELETE만 가능하다!
# ajax 요청 방식에 따른 파라미터 맵핑 방법.
https://hjho95.tistory.com/14 ajax settings
https://hjho95.tistory.com/7 application/x-www-form-urlencoded
https://hjho95.tistory.com/8 application/json
https://hjho95.tistory.com/9 form tag
https://hjho95.tistory.com/10 multipart/form-data
https://hjho95.tistory.com/12 PUT, PATCH, DELETE
https://hjho95.tistory.com/11 POST 방식으로 PUT, PATCH, DELETE 사용하기
# ajax 시리즈의 참조 페이지.
HiddenHttpMethodFilter: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/filter/HiddenHttpMethodFilter.html
'스프링 부트' 카테고리의 다른 글
[SpringBoot] Encrypt - AES128/256 ECB and CBC(with random iv) 테스트 코드 (2) | 2022.10.03 |
---|---|
[SpringBoot] jdk 1.8 > jdk 11 로 변경하기 (2) | 2022.09.12 |
[SpringBoot] ajax - PUT, PATCH, DELETE 로 요청하기! (0) | 2022.08.15 |
[SpringBoot] ajax - multipart/form-data 로 요청하기! (0) | 2022.08.14 |
[SpringBoot] ajax - html form tag 로 요청하기! (0) | 2022.08.13 |