본문 바로가기
공부/프로그래밍

[springboot] RestTemplate 를 사용할 때 401 에 body가 없는 경우(no body)

by demonic_ 2021. 8. 6.
반응형

RestTemplate를 통해 타 API를 호출해야하는데, 이 과정에서 401 에러가 발생할 경우 추가설정이 없는 한 다음과 같이 리턴이 온다.

org.springframework.web.client.HttpClientErrorException$Unauthorized: 401 : [no body]
...

문제는 401 에러안에 no Body 로 아무런 데이터가 없이 오는데, 내 경우 저 안에 로그인이 실패한 이유가 담겨서 와야한다. 실제로 통신을 하고나면 다음과 같은 통신이 일어난다.

[TestUserClient#userLogin] ---> POST http://localhost:9021/test/user/login HTTP/1.1
[TestUserClient#userLogin] Authorization: Basic aaaaaa==
[TestUserClient#userLogin] Content-Length: 56
[TestUserClient#userLogin] Content-Type: application/json
[TestUserClient#userLogin] 
[TestUserClient#userLogin] {"email":"test@naver.com","password":"test123"}
[TestUserClient#userLogin] ---> END HTTP (56-byte body)
[TestUserClient#userLogin] <--- HTTP/1.1 500  (299ms)
[TestUserClient#userLogin] cache-control: no-cache, no-store, max-age=0, must-revalidate
[TestUserClient#userLogin] connection: close
[TestUserClient#userLogin] content-type: application/json
[TestUserClient#userLogin] date: Tue, 03 Aug 2021 21:53:06 GMT
[TestUserClient#userLogin] expires: 0
[TestUserClient#userLogin] pragma: no-cache
[TestUserClient#userLogin] transfer-encoding: chunked
[TestUserClient#userLogin] x-content-type-options: nosniff
[TestUserClient#userLogin] x-frame-options: DENY
[TestUserClient#userLogin] x-xss-protection: 1; mode=block
[TestUserClient#userLogin] 
[TestUserClient#userLogin] {"errorCode": "E10007", "message":"비밀번호를 확인해 주세요."}
[TestUserClient#userLogin] <--- END HTTP (65-byte body)

 

로그를 보면 message 에 비밀번호를 확인해주세요 라고 리턴을 보내는데도 불구하고 RestTemplate 사용 시 401 에러가 발생하면 아무 메세지를 받지 못하는 것이다. 때문에 왜 로그인에 실패했는지에 대한 안내문구를 전달할 수 없었다.

 

그래서 이부분을 찾아보니 우선 HttpComponentsClientHttpRequestFactory 를 구현하여 restTemplate 에 설정하면 된다. 그러면 다음처럼 에러메세지에 보이게 된다.

설정하는 방법은 다음과 같다

...
RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
...

 

설정 전과 후를 비교하면 다음과 같다.

설정을 안했을 때

설정한 후

 

 

통신 중 성공이 아닌 에러가 발생하면 HttpClientErrorException 이 발생하고 여기에서 메세지가 위처럼 담기는 것이다. 메세지를 받는건 성공했는데 여전히 문제점이 남아 있다. 메세지를 꺼내도 JSON 형태가 아닌 401: [message] 형태로 고정되어 들어온다는 점인데, 401 에러에 한해서는 이렇게 들어온다 하더라도 다른 에러에 대해서는 명확한 핸들링이 현재로썬 불가능하단 점이다.

 

그래서 어떻게 하면 좋을까 하다가 우선 에러가 발생하면 Error 를 발생하여 HttpClientErrorException에 빠지는 것을 방지하고 아래에서 Status 를 참고하여 처리하면 되겠다 싶었다. 그렇게 될 경우 Response body 에 json 형태로 리턴받지 않을까 싶었다. 그래서 다음 파일을 추가한 다음 RestTemplate 설정에 추가했다.

 

OauthRestTemplateErrorHandler.java

public class OauthRestTemplateErrorHandler implements ResponseErrorHandler {
    @Override
    public boolean hasError(ClientHttpResponse response) throws IOException {
        HttpStatus statusCode = response.getStatusCode();
        return statusCode.series() == HttpStatus.Series.SERVER_ERROR;
    }

    @Override
    public void handleError(ClientHttpResponse response) throws IOException {
        ...
    }
}

RestTemplate 에 설정하기

...
RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
restTemplate.setErrorHandler(new OauthRestTemplateErrorHandler());
...

 

이후 실행해보면 HttpClientErrorException에 빠지는건 더이상 일어나지 않았다. 다만 httpStatus 따른 오류처리를 해줘야 하는데 다음처럼 수행했다.

ResponseEntity<String> response = resTemplate.postForEntity(...);

# 이 부분 추가
if (response.getStatusCode() != HttpStatus.OK) {
    // ... 정상이 아닐경우 처리
}

 

 

끝.

반응형

댓글