jwebserver — Java 단순 웹 서버 실행

jwebserver — Java 단순 웹 서버 실행 (JWebserver - Launch the Java Simple Web Server)

jwebserver는 단일 디렉터리 계층 구조를 서빙하는 최소한의 HTTP 서버를 제공하는 도구예요. 프로토타이핑·테스트·디버깅 용도로 설계되어 있어요. 이 문서에서는 이 도구의 사용법을 옵션별·예시별로 살펴봅니다.

출처: JWebserver - Launch the Java Simple Web Server

본문

jwebserver 소개

jwebserver — 단일 디렉터리 계층 구조를 서빙하는 최소한의 HTTP 서버를 제공하며, 프로토타이핑, 테스트, 디버깅을 염두에 둔 도구예요.

시놉시스 (Synopsis)

jwebserver [options]

options 의 옵션은 아래 jwebserver 항목에서 확인할 수 있어요.

사용 가능한 옵션은 다음과 같아요.

  • --bind-address addr 또는 —b addr 바인딩할 주소를 지정해요. 기본 주소는 127.0.0.1 또는 ::1 (루프백)이에요. 모든 인터페이스가 필요하다면 -b 0.0.0.0 또는 -b :: 를 쓰면 돼요.
  • --directory dir 또는 —d dir 서빙할 디렉터리를 지정해요. 기본값은 현재 디렉터리예요.
  • --help 또는 —h 전체 도움말 메시지를 출력해요.
  • --output level 또는 —o level 출력 형식을 지정하며, none | info | verbose 중 하나가 될 수 있어요. 기본값은 info 예요.
  • --port port 또는 -p port 리슨할 포트를 지정해요. 기본 포트 값은 8000이에요.
  • --version 도구의 축약된 버전 문자열을 출력해요.

설명 (Description)

jwebserver 는 프로토타이핑, 테스트, 디버깅에 쓸 수 있는 최소한의 HTTP 서버를 제공하는 JDK 도구예요. 이 도구는 정적 파일만 서빙하며, HTTP/1.1로 단일 디렉터리 계층 구조를 살펴봐요. 동적 콘텐츠나 다른 HTTP 버전은 지원하지 않아요.

jdk.httpserver 모듈에 jwebserver 가 포함되어 있어서, com.sun.net.httpserver 패키지의 웹 서버 구현을 기반으로 하기 때문에 java -m jdk.httpserver 로도 시작할 수 있어요.

SimpleFileServer 클래스는 서버와 그 구성 요소를 재사용하고 확장하기 위해 프로그래밍 방식으로 가져올 수 있는 방법을 제공해요. 자세한 내용은 working with the Simple Web Server API 섹션을 확인하세요.

서빙되는 요청 메서드는 멱등성(idempotent)이 있는 HEADGET 뿐이에요. 다른 요청을 시도하면 501 - Not Implemented 또는 405 - Not Allowed 응답을 받게 돼요.

이 도구는 GET 요청을 서빙 중인 디렉터리에 다음과 같이 매핑해요.

  • 요청한 리소스가 파일이면, 그 파일의 콘텐츠가 서빙돼요.
  • 요청한 리소스가 index 파일을 포함한 디렉터리면, 그 index 파일의 콘텐츠가 서빙돼요.
  • 그 외에는 응답에 디렉터리의 모든 파일·하위 디렉터리 이름이 담겨요. 심볼릭 링크와 숨김 파일은 나열되지도, 서빙되지도 않아요.

jwebserver 는 내장 테이블을 사용해 MIME 타입을 자동으로 구성해요. 예를 들어 .html 파일은 text/html 로, .java 파일은 text/plain 으로 서빙돼요.

커맨드라인 예시 (Command Line Examples)

jwebserver 는 다음과 같은 상황에서 도움이 돼요.

  • 웹 개발 테스트 — 클라이언트-서버 구성을 시뮬레이션할 로컬 테스트 서버가 필요할 때요.
jwebserver
Binding to loopback by default. For all interfaces use "-b 0.0.0.0" or "-b ::".
Serving /cwd and subdirectories on 127.0.0.1 port 8000
URL: http://127.0.0.1:8000/
  • 웹 서비스나 애플리케이션 테스트 — RESTful URL을 흉내 내고 더미 데이터를 담은 디렉터리 구조에 정적 파일을 API 스텁으로 사용할 때요.
jwebserver -p 9000
Binding to loopback by default. For all interfaces use "-b 0.0.0.0" or "-b ::".
Serving /youtube-jdk21 and subdirectories on 127.0.0.1 port 9000
URL http://127.0.0.1:9000/
127.0.0.1 - - [09/Jul/2023:13:02:05 +0200] "GET /api/activity.json HTTP/1.1" 200 -
127.0.0.1 - - [09/Jul/2023:13:02:06 +0200] "GET /api/activity.json HTTP/1.1" 200 -
  • 시스템 간 비공식적인 파일 브라우징·공유 — 예를 들어 로컬 머신에서 원격 서버의 디렉터리를 검색할 때요.
jwebserver -b 0.0.0.0
Serving /work and subdirectories on 0.0.0.0 (all interfaces) port 8000
URL http://192.168.178.41:8000/

커맨드라인 도구도 유용하지만, 기존 코드에서 Simple Web Server(즉, server, handler, filter)를 API로 사용할 수도 있어요.

Simple Web Server API 사용하기 (Working with the Simple Web Server API)

커맨드라인 도구인 jwebserver 외에도 Simple Web Server는 서버와 그 구성 요소를 프로그래밍 방식으로 만들고 커스터마이즈할 수 있는 API를 제공해요.

앞에서 jwebserver 명령이 현재 작업 디렉터리의 파일들을 서빙하는 모습을 봤죠. 그런데 가끔은 예상되는 응답 패턴을 시뮬레이션하면서도 그 mock을 실제로 디스크에 보존하지 않길 원할 때가 있어요. Google의 Java 인메모리 파일 시스템인 Jimfs 를 사용해 인메모리 리소스를 만들고, 그것을 Simple Web Server로 서빙하면 그런 동작을 얻을 수 있어요.

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.UUID;

import com.google.common.jimfs.Configuration;
import com.google.common.jimfs.Jimfs;
import com.sun.net.httpserver.SimpleFileServer;

import static com.sun.net.httpserver.SimpleFileServer.OutputLevel;

public class InMemoryFileServer {
    private static final InetSocketAddress LOOPBACK_ADDR =
            new InetSocketAddress(InetAddress.getLoopbackAddress(), 8080);
    public static final String JSON_FILE_NAME = "thing.json";
    public static final String DIR_PATH = "some/other";

    public static void main( String[] args ) throws Exception {
        Path root = createDirectoryHierarchy();
        var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR,  root, OutputLevel.VERBOSE);
        server.start();
        System.out.printf("http://%s:%d%n", server.getAddress().getHostString(), server.getAddress().getPort());
    }

    private static Path createDirectoryHierarchy() throws IOException {
        String json = """
                {
                  "activity": "Go for a run",
                  "type": "recreational",
                  "participants": 1,
                  "distance": "%d km",
                  "key": "%s",
                }
                """;
        FileSystem fs = Jimfs.newFileSystem(Configuration.unix());
        Path root = fs.getPath("/");
        Path dir = Files.createDirectories(root.resolve(DIR_PATH));
        Path filePath = fs.getPath(JSON_FILE_NAME);
        Path innerMockFile = Files.createFile(dir.resolve(filePath));

        Files.write(innerMockFile,json.formatted(12, UUID.randomUUID().toString()).getBytes(), StandardOpenOption.WRITE);
        Path mockFile = Files.createFile(dir.getParent().resolve(filePath));

        Files.write(mockFile,json.formatted(10, UUID.randomUUID().toString()).getBytes(), StandardOpenOption.WRITE);
        return root;
    }
}

앞선 코드 스니펫을 커맨드라인에서 실행하면:

$ java InMemoryFileServer.java
> http://127.0.0.1:8080

위 예시는 서버 메모리에 저장된 JSON 응답을 서빙해요. API 스터빙에 필요한 리소스를 제공하면서도 디스크 공간을 아끼는 방식이에요.

인메모리 자산을 서빙하는 또 다른 방법은 Christian Stein의 글에서 확인할 수 있는데, 그는 com.sun.net.httpserver.HttpHandler 를 구현해 인메모리 자산을 서빙해요.

Simple Web Server API를 사용하는 더 많은 프로그래밍 예시는 Julia Boes의 https://inside.java 글에서 볼 수 있어요.

더 알아보기 (Learn more)

  • 이 튜토리얼의 목차: jwebserver 소개 / 시놉시스 / 설명 / 커맨드라인 예시 / Simple Web Server API 사용하기 / 유용한 링크
  • 더 배우기(More Learning) 항목은 이 튜토리얼을 확장한 별도 페이지에서 확인할 수 있어요.