220428 TIL (CORS, PreFlight)

Minseok-Choi·2022년 4월 28일
0

TIL

목록 보기
8/11

학습자료

https://developer.mozilla.org/ko/docs/Web/HTTP/CORS
https://developer.mozilla.org/ko/docs/Glossary/Preflight_request

학습계기

  • 프론트와 협업하는 프로젝트를 진행 중에 login 관련해서 문제가 발생했다.
  • JWT 토큰을 구현하지는 않았지만, 일단은 interceptor를 통해서 검증을 하기 위해서 로그인이 성공하면 header에 userEmail을 담아주었고, 로그인이 필요한 API를 호출할 때는 header에 userEmail이 있는지를 확인하도록 했다.
  • 그 결과 다른 API에 대해서는 CORS 에러가 발생하지 않았지만, interceptor를 거치는 API만 CORS가 발생한다고 프론트쪽에서 말씀해주셨다.
Access to XMLHttpRequest at ‘http://domain:8080/orders/17’ from origin ‘http://localhost:3000’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
  • 이 전에도 Swagger를 적용했을 때 interceptor가 제대로 작동안했던 경험이 있어서, 바로 interceptor와 CORS에 관해서 검색해보고 그 이유를 알 수 있었다.

PreFlight

  • 한 문장으로 요약하면, 단순 요청(Simple request)이 아니라면 사전 요청(PreFlight)로 CORS 할 수 있는지 확인한다. 이 때 사전요청 또한 interceptor를 거치게 되는데 사전요청은 interceptor를 통과 할 때 필요로 하는 resource(나의 경우는 header)가 없었다. 그래서 프론트에는 CORS 에러를 받게 되는 것이었다.

  • 이 문제를 아주 쉽게 해결하는 방법은 interceptor의 로직에서 사전요청은 통과시키는 방법이다.

  • 여러 상황이 많다면 더 디테일한 조건이 필요하겠지만, 나는 HTTP method만을 확인해서 통과시키도록 구현했다.

  • 사전 요청은 OPTIONS 메서드이다. 그래서 method가 OPTIONS라면 통과시킨다.

 @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
        Object handler) throws Exception {
        
        if(HttpMethod.OPTIONS.matches(request.getMethod())) {
            return true;
        }
        
        ...
  • 사전요청은 Access-Control-Request-Method,
    Access-Control-Request-Headers, Origin 이렇게 총 3가지의 HTTP request headers를 사용하고, OPTIONS method를 사용한다.
  • 사전 요청은 브라우저에서 자동적으로 발생시키는데, Simple Request (단순 요청)의 경우에는 생략된다.
  • 사전 요청을 보내고 허락된다면, 서버에서는 가능한 메서드들을 응답헤더에 담아서 반환한다.(CORS 매핑한 조건)
HTTP/1.1 204 No Content
Connection: keep-alive
Access-Control-Allow-Origin: https://foo.bar.org
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE
Access-Control-Max-Age: 86400

Simple Response (단순 요청)

  • 위에서 언급했듯이, preFlight를 보내지 않는 simple response가 되기위해서는 조건들이 있다.
  • HTTP method는 GET, POST, HEAD만 가능하다.
  • header는 User-agent가 자동으로 설정한 헤더이외에, Accept, Accept-Language, Content-Language, Content-Type 만을 허용한다.
  • Content-Typeapplication/x-www-form-urlencoded, multipart/form-data, text/plain만 허용한다.

    https://fetch.spec.whatwg.org/#cors-safelisted-request-header

  • 또한 요청에 readableStream이 사용되지 않는다.
  • If the request is made using an XMLHttpRequest object, no event listeners are registered on the object returned by the XMLHttpRequest.upload property used in the request; that is, given an XMLHttpRequest instance xhr, no code has called xhr.upload.addEventListener() to add an event listener to monitor the upload.
    (이해못함)

TODO

  • 사실 CORS 매핑에 대해서 필요한 부분이라해서, 얼추 이해하고 모든 API, 모든 헤더, 모든 origin을 허용하다록 CORS 매핑을 해주었다. 정확하게 그 의미를 이해하지 못했다.
  • 그러니 당연하게 preFlight에 관해서도 몰랐다.
  • 역시 뭐든 알고쓰고, 서버를 구동하면서 log를 잘 남기는 것이 중요하다라는 것을 깨닫게 되었다.
  • 또한 swagger와 관련해서 interceptor가 작동하지 않았던 삽질이 의미가 있었다는 생각이 새삼든다..
  • 정리를하자정리..
profile
차곡차곡

0개의 댓글