text/Java

@ResponseStatus 204 No Content

hoonzii 2023. 3. 1. 21:12
반응형

tl;dr

SpringBoot controller에서 결과값을 반환하지 않을 때는

 

Return HTTP 204 on null with spring @RestController

This returns 200 OK with Content-Length: 0 @RestController public class RepoController { @RequestMapping(value = "/document/{id}", method = RequestMethod.GET) public Object getDocument(@

stackoverflow.com

 

 

옛날에 만든 프로젝트를 스프링부트로 옮기는 와중에 이전 코드에 존재하는 동작중

parameter로 값을 넘겨주면 해당 값을 DB 조회해 받아온 값으로 엑셀로 만들어 다운로드할 수 있게

만들어 둔 게 있었다.

문제는 다운로드 파일을 서버에 한번 저장한 다음 해당 파일 경로를 바로 접근한다는 게 오늘의 오류의 발생 지점이었다.

  1. controller는 파라미터를 받아 조회 후 엑셀을 생성, 서버 내 폴더 저장
  2. 해당 작업이 완료되면 서버에 요청해 해당 파일을 다운로드하게 구성

다른 controller와 달리 이건 반환 값이 없다! ajax 요청 후, 반환값이 없으니 계속 오류가 뜨는 거다.

해당 오류를 재현하게 단순한 프로젝트를 구성해 보자.

  1. 페이지에서 parameter( int a, b)로 값을 전달 (ajax 이용)
  2. 전달한 값을 더해 파일(txt)에 적은 뒤, 서버에 저장 (spring boot folder 내 저장)
  3. 해당 파일을 다운로드

 

오류 재현을 위해

spring boot initializer를 이용해 프로젝트를 구성

사진에 보는 것과 구성한 뒤, 프로젝트 빌드

프로젝트의 폴더 구조는 아래와 같다.

이제 html, js, controller를 구성해 준다.

1. 먼저 home.html

<html>
<head>
    <title>test</title>
    <script src="https://code.jquery.com/jquery-3.6.3.min.js" integrity="sha256-pvPw+upLPUjgMXY0G+8O0xUf+/Im1MZjXxxgOcBQBXU=" crossorigin="anonymous"></script>
</head>
<body>
    test page!
    <br>
    a : <input type="text" id="input_a"/>
    <br>
    b : <input type="text" id="input_b"/>
    <input type="button" id="button" value="download"/>
    <a id='download' href="" download = "" style="display: none;"/>
</body>
<script type="text/javascript" src="./home.js"></script>
</html>

2. 이제 home.js

$(document).ready(function() {
    console.log("home!")
    addAndSave();
});

// download 버튼 누를때 동작하게끔 구성
function addAndSave(){
    $("#button").on("click", function() {
        let a = $("#input_a").val();
        let b = $("#input_b").val();
        console.log(a,b);
        let filename = "test.txt";
        $.ajax({
            url : "addAndSave",
            method : "GET", // get 동작으로 서버에 요청
            data : {
                a : a,
                b : b,
                filename : filename
            },
        }).done(function() {
            $("#download").attr("href","file/"+filename);
            $("#download").attr("download", filename);
            document.getElementById("download").click();
        });
    });
}

 

3. controller의 GetMapping

@Autowired
ResourceLoader resourceLoader;

@GetMapping("/addAndSave")
public void addAndSave(
        @RequestParam("a") int a,
        @RequestParam("b") int b,
        @RequestParam("filename") String filename
) throws IOException {
    String folderPath = resourceLoader.getResource("classpath:static/file").getURI().getPath();
    File file = new File(folderPath, filename);
    String text = "a = "+a+", b = "+ b + ", a+b = "+(a+b);
    FileWriter fw = new FileWriter(file);
    fw.write(text);
    fw.close();
}

 

이제 html에 숫자를 입력한 뒤, download 버튼을 누르면

target 폴더 내 test.txt 가 생성되어 파일이 존재하는 걸 확인할 수 있다.

문제는 반환값이 존재하지 않기 때문에 웹페이지 상에서는 404 에러가 뜬다.

 

찾아보니 SpringBoot controller에서 결괏값을 반환하지 않을 때는
https://stackoverflow.com/questions/32396884/return-http-204-on-null-with-spring-restcontroller

 

Return HTTP 204 on null with spring @RestController

This returns 200 OK with Content-Length: 0 @RestController public class RepoController { @RequestMapping(value = "/document/{id}", method = RequestMethod.GET) public Object getDocument(@

stackoverflow.com

함수 위에 해당 요청은 반환값이 없다는 걸 알려줘야 한다.

@GetMapping("/addAndSave")
@ResponseStatus(value= HttpStatus.NO_CONTENT)
public void addAndSave(
 // blar blar~~

 

위 annotation 추가 후 동작하면

해당 GET 요청 시 204 statusCode를 반환하고 이전처럼 에러가 나지 않는다.

물론 파일 다운로드도 정상적으로 되는 걸 확인할 수 있다. (테스트 때문에 동일 파일이름이 존재해서 (2))

 

 

그럼 204 NO Content 응답에 대해서 좀 더 확인해 보자.

https://ko.wikipedia.org/wiki/HTTP_%EC%83%81%ED%83%9C_%EC%BD%94%EB%93%9C

 

HTTP 상태 코드 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 아래는 HTTP(하이퍼텍스트 전송 프로토콜) 응답 상태 코드의 목록이다. IANA가 현재 공식 HTTP 상태 코드 레지스트리를 관리하고 있다. 모든 HTTP 응답 코드는 5개의

ko.wikipedia.org

보통은 DELETE 나 PUT 요청에 사용된다고 하는데…

나처럼 무언가 반환할 값이 없을 때도 사용하면 될듯하다 (꼭 DELETE 요청이 아니더라도…)

반응형