Backend/Spring

[김영한 Spring MVC 1편] HTTP 요청 데이터

박상윤 2024. 4. 26. 15:09

2024/04/26

HTTP 요청 데이터 - 개요

HTTP 요청 메시지를 통해 클라이언트에서 서버로 데이터를 전달하는 방법

 

주로 3가지 방법을 사용한다.

 

(1) GET 쿼리 파라미터

/url"?username=hello&age=20"

메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달

ex) 검색, 필터, 페이징등에서 많이 사용하는 방식

 

(2) POST - HTML Form

content-type: application/x-www-form-urlencoded

메시지 바디에 쿼리 파라미터 형식으로 전달 username=hello&age=20

ex) 회원 가입, 상품 주문, HTML Form 사용

 

(3) HTTP message body에 데이터를 직접 담아서 요청

HTTP API에서 주로 사용, JSON, XML, TEXT

데이터 형식은 주로 JSON 사용

POST, PUT, PATCH

HTTP 요청 데이터 GET 쿼리 파라미터

전달 데이터

- username=hello

- age=20

 

메시지 바디 없이, URL의 쿼리 파라미터를 사용해서 데이터를 전달

ex) 검색, 필터, 페이징등에서 많이 사용하는 방식

 

쿼리 파라미터는 URL에 다음과 같이 ?를 시작으로 보낼 수 있다. 추가 파라미터는 &로 구분하면 된다.

ex) http://localhost:8080/request-param?username=hello&age=20

 

서버에서는 HttpServletRequest가 제공하는 다음 메서드를 통해 쿼리 파라미터를 편리하게 조회할 수 있다.

 

쿼리 파라미터 조회 메서드

String username = request.getParameter("username"); // 단일 파라미터 조회
Enumeration<String> parameterNames = request.getParameterNames(); // 파라미터 이름을 모두 조회
Map<String, String[]> parameterMap = request.getParameterMap(); // 파라미터를 Map으로 조회
String[] usernames = request.getParameterValues("username"); // 복수 파라미터 조회

 

 

RequestParamServlet

package com.example.servlet.basic.request;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

/**
 * 1. 파라미터 전송 기능
 * http://localhost:8080/request-param?username=hello&age=20
 */
@WebServlet(name = "requestParamServlet", urlPatterns = "/request-param")
public class RequestParamServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Enumeration<String> parameterNames = request.getParameterNames();
        System.out.println("RequestPramServlet.servicer");

        System.out.println("[전체 파라미터 조회] - start");
        request.getParameterNames().asIterator()
                        .forEachRemaining(paraName -> System.out.println(paraName + "=" + request.getParameter(paraName)));

        System.out.println("[전체 파라미터 조회] - end");
        System.out.println();

        System.out.println("[단일 파라미터 조회] - start");
        String username = request.getParameter("username");
        System.out.println("username = " + username);
        String age = request.getParameter("age");
        System.out.println("age = " + age);
        System.out.println("[단일 파라미터 조회] - end");
        System.out.println();

        System.out.println("[이름이 같은 복수 파라미터 조회]");
        String[] usernames = request.getParameterValues("username");
        for (String name : usernames) {
            System.out.println("name = " + name);
        }

        response.getWriter().write("OK");
    }
}

 

출력 결과

 

복수 파라미터에서 단일 파라미터 조회

username=hello&username=kim 과 가티 파라미터 이름은 하나이지만, 값이 중복되면 값을 어덯게 가져올까?

request.getParameter()는 하나의 파라미터 이름에 대해서 단 하나의 값만 있을 때 사용해야 한다. 지금처럼 중복일때는 request.getParameterValues()를 사용해야 한다.

중복일때 request.getParameter()를 사용하면 request.getParameterValues()의 첫 번째 값을 반환한다.

 

중복으로는 거의 사용하지 않는다.

 

HTTP 요청 데이터 - POST HTML Form

HTML의 Form을 사용해서 클라이언트에서 서버로 데이터를 전송해보자.

주로 회원 가입, 상품 주문 등에서 사용하는 방식이다.

 

특징

(1) content-type: application/x-www-form-urlencoded

(2) 메시지 바디에 쿼리 파라미터 형식으로 데이터를 전달한다. username=hello&age=20

 

src/main/webapp/basic/hello-form.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/request-param" , method="post">
        username : <input type="text" name="username"/>
        age: <input type="text" name="age"/>
        <button type="submit">전송</button>
    </form>
</body>
</html>

 

접속 url: http://localhost:8080/basic/hello-form.html

출력 결과

username : kim 입력

age : 20 입력

 

전송 하면 나오는 결과

 

POST의 HTML Form을 전송하면 웹 브라우저는 다음 형식으로 HTTP 메시지를 만든다.

요청 URL : http://localhost:8080/request-param

content-type : application/x-www-form-urlencoded

message body : username=hello&age=20

 

application/x-www-form-urlencoded  형식은 GET에서 살펴본 쿼리 파라미터 형식과 같다.

쿼리 파라미터 조회 메서드를 그대로 사용하면 된다.

클라이언트(웹 브라우저) 입장에서는 두 방식에 차이가 있지만, 서버 입장에서는 둘의 형식이 동일하므로, request.getParameter()로 편리하게 구분없이 조회할 수 있다.

 

request.getParameter()는 GET URL, 쿼리 파라미터 형식도 지원하고, POST HTML Form 형식도 둘 다 지원한다.

 

content-type은 HTTP 메시지 바디의 데이터 형식을 지정한다.
GET URL 쿼리 파라미터 형식으로 클라이언트에서 서버로 데이터를 전달할 때는 HTTP 메시지 바디를 사용하지 않기 때문에
content-type이 없다.
POST HTML Form 형식으로 데이터를 전달하면 HTTP 메시지 바디에 해당 데이터를 포함해서 보내기 때문에 바디에 포함된 데이터가
어떤 형식인지 content type을 꼭 지정해야 한다. 폼으로 데이터를 전송하는 형식을 application/x-www.form-urlencoded라 한다.

 

2024/05/03

HTTP 요청 데이터 - API 메시지 바디 - 단순 텍스트

HTTP message body에 데이터를 직접 담아서 요청

  • HTTP API에서 주로 사용, JSON, XML, TEXT
  • 데이터 형식은 주로 JSON 사용
  • POST, PUT, PATCH

HTTP 메시지 바디의 데이터를 InputStream을 사용해서 직접 읽을 수 있다.

 

RequestBodyStringServlet

package com.example.servlet.basic.request;

import jakarta.servlet.ServletException;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.springframework.util.StreamUtils;

@WebServlet(name = "requestBodyStringServlet", urlPatterns = "/request-body- string")
public class RequestBodyStringServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        ServletInputStream inputStream = req.getInputStream();
        String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
        System.out.println("messageBody = " + messageBody);
        resp.getWriter().write("ok");
    }
}

 

참고
inputStream은 byte 코드를 반환한다. byte 코드는 읽을 수 있는 문자(String)로 보려면 문자표(Charset)를 지정해 주어야 한다.
여기서는 UTF-8 Charset을 지정해주었다.

 

 

문자 전송

  • POST http://localhost:8080/request-body-string
  • content-type : text/plain
  • message body : hello
  • 결과 : messageBody = hello

Postman 요청 보내기

출력문

 

HTTP 요청 데이터 - API 메시지 바디 - JSON

HTTP API에서 주로 사용하는 JSON 형식으로 데이터를 전달

 

JSON 형식 전송

  • POST http://localhost:8080/request-body-json
  • content-type : application/json
  • message body : { "username" : "hello", "age":20}
  • 결과 : messageBody = { "username" : "hello", "age" : 20}

JSON 형식 파싱 추가

JSON 형식으로 파싱할 수 있게 객체를 생성

 

 

HelloData

package com.example.servlet.basic.dto;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class HelloData {

    private String username;
    private int age;
}

 

lombok이 제공하는 @Getter, @Setter 덕에 다음 코드가 추가된다.

package hello.servlet.basic;
 public class HelloData {
     private String username;
     private int age;
//==== lombok 생성 코드 ====//
	
    public String getUsername() {
         return username;
     }
    public void setUsername(String username) {
         this.username = username;
	 }
    public int getAge() {
         return age;
	 }
    public void setAge(int age) {
         this.age = age;
	 }
}

 

 

RequestBodyJsonServlet

package com.example.servlet.basic.request;

import com.example.servlet.basic.dto.HelloData;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.springframework.util.StreamUtils;

@WebServlet(name = "requestBodyJsonServlet", urlPatterns = "/request-body-json")
public class RequestBodyJsonServlet extends HttpServlet {

    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletInputStream inputStream = req.getInputStream();
        String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);

        System.out.println("message body : " + messageBody);

        HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);

        System.out.println("helloData.username = " + helloData.getUsername());

        resp.getWriter().write("ok");
    }
}

 

Postman으로 실행

  • POST http://localhost:8080/request-body-json
  • content-type : application/json
  • message body :  { "username" : "hello", "age" : 20 }

출력 결과

 

참고
JSON 결과를 파싱해서 사용할 수 있는 Java 객체로 변환하려면 Jackson, Gson과 같은 JSON 변환 라이브러리를 추가해서 사용해야 한다. 스프링 부트로 Spring MVC를 선택하면 기본적으로 Jackson 라이브러리 (ObjectMapper)를 함께 제공한다.

 

참고
HTML form 데이터도 메시지 바디를 통해 전송되므로 직접 읽을 수 있다. 편리한 파라미터 조회 기능
(request.getParameter(..))을 이미 제공하므로 파라미터 조회 기능을 사용하면 된다.