티스토리 뷰

HTTP Request 중 message-body로 넘어온 parameter 확인을 위해서는 getInputStream() 이나 getReader()를 사용합니다.


이번 프로젝트에서 사용자가 서비스에 접근하여 어떤 기능들을 수행했는지 로그를 남기는 기능을 구현하던 중 getInputStream() 사용 후 parameter가 손실되는 현상이 있어 공유하고자 합니다.


서비스의 구조는 Spring MVC로 되어있습니다.




여기에서 Controller로 요청이 들어가기 전 URL 및 Parameter 취득을 위해 Interceptor를 구현하였습니다.




Interceptor에서 body에 있는 parameter 취득을 위해 구현한 소스는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
String parameter = null;
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
    InputStream inputStream = request.getInputStream();
    if (inputStream != null) {
        bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        char[] charBuffer = new char[128];
        int bytesRead = -1;
        while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
            stringBuilder.append(charBuffer, 0, bytesRead);
        }
    }
catch (IOException ex) {
    throw ex;
finally {
    if (bufferedReader != null) {
        try {
            bufferedReader.close();
        } catch (IOException ex) {
            throw ex;
        }
    }
}
parameter = stringBuilder.toString();
cs


문제는 이후에 발생합니다.


갑자기 잘 되던 Controller에서 HTTP POST로 전달해 온 parameter를 찾을 수 없어 NullPointException이 발생하는 것입니다. 확인해 보니 Interceptor에서 이미 getInputStream()을 사용하여 body를 읽어드렸기 때문에 Controller에서는 아무것도 반환하지 않게 된 것이죠.


ServletRequest#getParameter 문서를 보시면 해당 현상에 대한 설명이 있습니다.


If the parameter data was sent in the request body, such as occurs with an HTTP POST request, then reading the body directly via getInputStream() or getReader() can interfere with the execution of this method.


그렇다면 어떤 식으로 body의 내용을 확인하는 것이 좋을까요?

getParameterNames() 나 getParameterMap()을 사용하면 parameter 손실을 막을 수 있습니다.


- getParameterNames()를 사용한 예

1
2
3
4
5
String parameter;
for (String name : Collections.<String>list(request.getParameterNames())) {
    String value = request.getParameter(name); 
    parameter += name + "=" + value + "&";
}
cs


- getParameterMap()을 사용한 예

1
2
3
4
5
6
7
String parameter;
Map<StringString[]> map = request.getParameterMap();
for (Entry<StringString[]> entry : map.entrySet()) {
    String name = entry.getKey();
    String[] values = entry.getValue();
    parameter += name + "=" + Arrays.toString(values) + "&";
}
cs


두 방법 중 어느 방법을 사용하셔도 무방합니다.

개인적으로는 getParameterNames()를 사용하는 것이 소스가 간결해지고 리턴 되는 결과도 깔끔해서 좋더군요.


참조

http://stackoverflow.com/questions/10210645/http-servlet-request-lose-params-from-post-body-after-read-it-once

http://stackoverflow.com/questions/3769259/why-is-the-parameter-value-an-object-hash-code-for-request-getparametermap-ge

'개발 > JAVA' 카테고리의 다른 글

HttpServletRequest 함수를 사용한 요청 URL 취득  (0) 2015.03.18
최근에 올라온 글
Total
Today
Yesterday
링크