Java SE API 만 사용하는 Java의 단순 HTTP 서버


333

HTTP 요청을 수동으로 구문 분석하고 HTTP 응답을 수동으로 형식화하는 코드를 작성하지 않고 Java SE API 만 사용하여 Java에서 매우 기본적인 HTTP 서버 (GET / POST 만 지원)를 작성하는 방법이 있습니까? Java SE API는 HttpURLConnection의 HTTP 클라이언트 기능을 훌륭하게 캡슐화하지만 HTTP 서버 기능에 대한 아날로그가 있습니까?

분명히 내가 온라인에서 본 많은 ServerSocket 예제의 문제점은 지루하고 오류가 발생하기 쉽고 포괄적이지 않을 수있는 자체 요청 구문 분석 / 응답 형식 지정 및 오류 처리를 수행한다는 것입니다. 나는 그런 이유로 그것을 피하려고 노력하고 있습니다.

내가 피하려고하는 수동 HTTP 조작의 예 :

http://java.sun.com/developer/technicalArticles/Networking/Webserver/WebServercode.html


3
음 ... 짧은 대답은 '아니요'입니다. http 헤더를 수동으로 쓰지 않고 게시물을 처리하고 요청을 처리하는 것을 원한다면 서블릿을 사용할 수 있습니다. 그러나 그것은 자바 ee입니다. 그런 것을 사용하고 싶지 않다면 소켓과 수동 구문 분석이 내가 아는 유일한 다른 옵션입니다.
Matt Phillips

3
나는 이것이 SO의 정신에 있지 않다는 것을 알고 있지만 Java EE API에 대한 열망을 재고하도록 권고합니다. 일부 답변에서 언급했듯이 Jetty와 같이 매우 직설적 인 구현이있어 서블릿 API를 활용하면서 독립 실행 형 응용 프로그램에 웹 서버를 포함시킬 수 있습니다. 어떤 이유로 든 Java EE API를 절대 사용할 수 없다면 내 의견을 무시하십시오. :-)
Chris Thompson

1
"서블릿"은 실제로 "Java EE"가 아닙니다. 메시지 활동 (일반적으로 HTTP 요청)에 응답하여 주변 애플리케이션에서 호출 할 수있는 플러그인을 작성하는 방법 일뿐입니다. "Java SE API 만 사용하여"서블릿 호스팅 환경을 제공하는 것은 Jetty와 Tomcat이하는 일입니다. 물론 원치 않는 복잡성을 없애고 싶지만 GET / POST의 허용되는 속성 및 구성의 하위 집합을 결정해야 할 수도 있습니다. 특별한 보안 / 임베디드 문제를 제외하고는 종종 가치가 없습니다.
David Tonhofer

1
결정하기 전에이 http 서버 목록을 살펴볼 가치가 있습니다. java-source.net/open-source/web-servers
ThreaT

답변:


469

Java SE 6부터 Sun Oracle JRE 에 내장 HTTP 서버가 있습니다. com.sun.net.httpserver패키지의 개요는 침범 된 클래스를 설명하고 예제가 포함되어 있습니다.

다음 은 문서에서 복사하여 붙여 넣은 시작 예입니다 (그럼에도 불구하고 편집하려고하는 모든 사람들에게) 원본에서). Java 6 이상에서 복사하여 붙여 넣기를 실행할 수 있습니다.

package com.stackoverflow.q3732109;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class Test {

    public static void main(String[] args) throws Exception {
        HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
        server.createContext("/test", new MyHandler());
        server.setExecutor(null); // creates a default executor
        server.start();
    }

    static class MyHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange t) throws IOException {
            String response = "This is the response";
            t.sendResponseHeaders(200, response.length());
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }

}

response.length()그들의 예 에서 부분이 나쁘다는 것을 주목해야한다 response.getBytes().length. 그럼에도 불구하고 getBytes()메소드는 명시 적으로 문자 세트를 지정해야하며 응답 헤더에 지정해야합니다. 아아, 초보자에게는 오해가 있지만 결국 기본적인 킥오프 예제입니다.

그것을 실행하고 http : // localhost : 8000 / test 로 이동 하면 다음과 같은 응답이 나타납니다.

이것은 응답입니다


com.sun.*클래스 사용과 관련하여 이는 일부 개발자의 생각과 달리 잘 알려진 FAQ에서 개발자가 'sun'패키지를 호출하는 프로그램을 작성해서는 안되는 이유 는 절대로 금지하지 않습니다 . 이 FAQ는 sun.*패키지가 sun.misc.BASE64Encoder아닌 Oracle JRE의 내부 사용을위한 패키지 (예 :)와 관련이 있습니다 (따라서 다른 JRE에서 실행할 때 응용 프로그램이 종료 됨) com.sun.*. Sun / Oracle은 Apache 등과 같은 다른 모든 회사와 마찬가지로 Java SE API 자체에서 소프트웨어를 개발하기 만합니다. GlassFish (Java EE impl), Mojarra (JSF impl), Jersey (JAX-RS impl) 등과 같은 특정 Java API 구현com.sun.*관련 하여 클래스를 사용하는 것은 권장되지 않지만 금지되지는 않습니다 .


19
@Waldheinz : @Software와 같이 혼동 sun.*합니다 com.sun.*. 예를 들어 sun.*API 문서가 있습니까? 여기를보십시오 : java.sun.com/products/jdk/faq/faq-sun-packages.html 그것에 대해 아무 말이 com.sun.*있습니까? 은 com.sun.*단지 자바 API의 일부가 아닌 자신의 공개 소프트웨어에 사용됩니다. 또한 다른 회사와 마찬가지로 Java API를 기반으로 소프트웨어를 개발합니다.
BalusC

4
나는 이것이 통합 테스트 사례에서 사용하기에 아주 좋은 http 서버라고 생각합니다. 힌트 주셔서 감사합니다!
Andreas Petersson

13
Eclipse를 사용 중이고 "액세스 제한 : 필수 라이브러리 제한으로 인해 HttpExchange 유형에 액세스 할 수 없습니다 ..."와 같은 오류가 발생하면 stackoverflow.com/a/10642163에서 해당 액세스 확인을 비활성화하는 방법을 알려줍니다.
Samuli Pahaoja

13
FWIW 이것은 OpenJDK에도 있습니다.
Jason C

6
여기에 언급 된 클래스 @jdk.Exported는 OpenJDK 소스 코드에 태그 되어 있으며 이는 API가 공개 된 것으로 간주되며 Java 9에서 사용 가능함을 의미합니다 (일부 다른 com.sun.*패키지는 Project Jigsaw로 인해 사용할 수 없게 됨).
Jules

42

NanoHttpd를 확인하십시오

"NanoHTTPD는 Modified BSD 라이센스하에 릴리스 된 다른 응용 프로그램에 포함되도록 설계된 경량 HTTP 서버입니다.

Github에서 개발 중이며 빌드 및 유닛 테스트에 Apache Maven을 사용합니다. "


4
한 가지주의 사항 : NanoHTTPD에는 트리 워킹 공격에 대한 보호 기능이 없을 수 있습니다. 공개 주소로 서비스를 제공하는지 확인해야합니다. 즉, 요청 GET /../../blahblah http/1.1이 발생하고 서버가 웹 사이트 루트를 넘어 시스템 파일 랜드로 이동하여 암호 파일과 같이 시스템을 손상 시키거나 원격으로 공격하는 데 사용할 수있는 파일을 제공하는 공격을 의미합니다.
Lawrence Dol

7
그것은 고정 된 것 같습니다. 현재 버전은 if (uri.startsWith ( "..") || uri.endsWith ( "..") || uri.indexOf ( "../")> = 0) 403을 생성합니다.
레나 Schimmel

5
이것이 이것이이 질문에 어떻게 대답하는지 이해하지 못합니다.
kimathie

28

com.sun.net.httpserver의의 솔루션은 JRE에 걸쳐 이식 할 수 없습니다. javax.xml.ws 의 공식 웹 서비스 API를 사용하여 최소한의 HTTP 서버를 부트 스트랩하는 것이 좋습니다 ...

import java.io._
import javax.xml.ws._
import javax.xml.ws.http._
import javax.xml.transform._
import javax.xml.transform.stream._

@WebServiceProvider
@ServiceMode(value=Service.Mode.PAYLOAD) 
class P extends Provider[Source] {
  def invoke(source: Source) = new StreamSource( new StringReader("<p>Hello There!</p>"));
}

val address = "http://127.0.0.1:8080/"
Endpoint.create(HTTPBinding.HTTP_BINDING, new P()).publish(address)

println("Service running at "+address)
println("Type [CTRL]+[C] to quit!")

Thread.sleep(Long.MaxValue)

편집 : 이것은 실제로 작동합니다! 위의 코드는 Groovy 또는 다른 것 같습니다. 테스트 한 Java 로의 번역은 다음과 같습니다.

import java.io.*;
import javax.xml.ws.*;
import javax.xml.ws.http.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;

@WebServiceProvider
@ServiceMode(value = Service.Mode.PAYLOAD)
public class Server implements Provider<Source> {

    public Source invoke(Source request) {
        return  new StreamSource(new StringReader("<p>Hello There!</p>"));
    }

    public static void main(String[] args) throws InterruptedException {

        String address = "http://127.0.0.1:8080/";
        Endpoint.create(HTTPBinding.HTTP_BINDING, new Server()).publish(address);

        System.out.println("Service running at " + address);
        System.out.println("Type [CTRL]+[C] to quit!");

        Thread.sleep(Long.MAX_VALUE);
    }
}

1
휴대하기 +1 응답 콘텐츠 유형을 그대로 설정할 수 없습니다 text/xml.
icza

1
<code> class Server가 Provider <DataSource> {</ code> ...를 구현 한 다음 DataSource의 <code> getContentType () </ code> 메소드에서 Content-Type을 지정할 수 있다고 생각합니다. 또한 WebServiceContext : <code> @Resource WebServiceContext ctx; </ code>를 삽입하여 다른 헤더를 설정하고 요청 매개 변수를 읽을 수도 있습니다. 불행히도 WebServiceContext를 통해 컨텐츠 유형을 설정하면 작동하지 않습니다.
gruenewa

4
com.sun.net.HttpServer가 JRE에서 이식성이없는 이유를 설명해 주시겠습니까?
javabeangrinder

3
아니, 난 그렇게 생각하지 않아 IBM의 Java 구현 및 기타 기능에서는 작동하지 않습니다. 그리고 지금 작동하더라도 내부 API를 변경할 수 있습니다. 왜 공식 API를 사용하지 않습니까?
gruenewa

1
이 링크 : docs.oracle.com/javase/9/docs/api/java.xml.ws-summary.html에 따르면 java.xml.ws 모듈은 Java 9부터 더 이상 사용되지 않습니다.
Erel Segal-Halevi

23

이 질문은 지속적인 혁신이 진행되는 영역이며 특히 소형 장치의 내장 서버에 대해 이야기 할 때 항상 가벼운 서버가 필요하기 때문에이 질문이 마음에 듭니다. 답은 두 가지 그룹으로 나뉜다 고 생각합니다.

  1. Thin-server : 최소한의 처리, 컨텍스트 또는 세션 처리로 서버 업 정적 컨텐츠.
  2. 작은 서버 : 표면 상으로는 작은 공간을 차지하는 httpD와 유사한 서버 품질이 많이 있습니다.

Jetty , Apache Http Components , Netty 및 기타와 같은 HTTP 라이브러리 는 원시 HTTP 처리 기능과 비슷하다고 생각할 수 있습니다. 라벨링은 매우 주관적이며 소규모 사이트에 제공하기 위해 전화를 한 종류에 따라 다릅니다. 나는 질문의 정신, 특히 다음에 대한 언급 에서이 구별을합니다 ...

  • "... 수동으로 HTTP 요청을 구문 분석하고 HTTP 응답의 형식을 지정하는 코드를 작성하지 않고 ..."

이 원시 도구를 사용하면 다른 답변에서 설명한 것처럼 그렇게 할 수 있습니다. 그들은 실제로 소형, 내장형 또는 소형 서버를 만들 준비가 된 스타일에 적합하지 않습니다. 미니 서버는 종소리와 휘파람, 볼륨이 적고 성능이 99 % 인 풀 기능 웹 서버 (예 : Tomcat 등 ) 와 유사한 기능을 제공 할 수있는 기능 입니다. 씬 서버는 원래의 문구에 더 가깝게 보일 것입니다. 아마도 제한된 하위 집합 기능을 사용하여 시간의 90 %를 멋지게 보일 수 있습니다. 생생한 아이디어는 추가 디자인과 코딩 없이도 시간의 75 %-89 %를 멋지게 보이게하는 것입니다. WAR 파일 수준에 도달하면 큰 서버가 작게 만드는 모든 것 같은 Bonsi 서버에 대해 "작은"상태를 유지했다고 생각합니다.

씬 서버 옵션

미니 서버 옵션 :

  • Spark Java ... 필터, 템플릿 등과 같은 많은 도우미 구성으로 좋은 일이 가능합니다.
  • MadVoc ... 분재를 목표로하고 잘 될 수 있습니다 ;-)

고려해야 할 사항 중에는 FreeMaker 또는 기타 템플릿 도구를 사용하여 페이지 출력을 렌더링하는 인증, 유효성 검사, 국제화가 포함됩니다 . 그렇지 않으면 HTML 편집 및 매개 변수화를 관리하면 HTTP 작업이 noughts-n-crosses처럼 보일 수 있습니다. 당연히 모든 것이 얼마나 유연해야하는지에 달려 있습니다. 메뉴 방식의 팩스 기기라면 매우 간단 할 수 있습니다. 상호 작용이 많을수록 프레임 워크가 ' 두꺼워 '져야합니다. 좋은 질문, 행운을 빌어 요!


21

"Jetty"웹 서버 Jetty를 살펴보십시오 . 모든 요구 사항을 충족하는 것처럼 보이는 훌륭한 오픈 소스 소프트웨어입니다.

당신이 자신의 롤링을 주장한다면 "httpMessage"클래스를 살펴보십시오.


나는 부두 API가 서블릿에 달려 있다고 생각합니다.
평판이 좋은

4
@Irreputable : 아닙니다. Jetty는 모듈 식 웹 서버로, 옵션 모듈 중 하나 인 서블릿 컨테이너가 있습니다.
Lawrence Dol

"이것은 서버 기능에 대한 아날로그입니다"- "서블릿"API입니다. 서블릿 컨테이너는 헤더, 쿠키 등을 구문 분석 한 후 클래스를 호출합니다.
James Anderson

1
그냥 기록을 위해 - 부두는 서블릿 API의 자신의 구현을 제공 및 Java SE와 함께 잘 작동합니다
제임스 앤더슨

4
부두가 너무 커서 실제 생산 사용이 가능해지기 전에 학습 곡선이 너무 많습니다.
ThreaT

18

옛날 옛적에 나는 쉽게 포함하고 사용자 정의 할 수있는 가볍지 만 완전한 기능을 갖춘 HTTP 서버와 비슷한 것을 찾고있었습니다. 두 가지 유형의 잠재적 솔루션을 찾았습니다.

  • 가볍거나 단순하지 않은 전체 서버 (가벼운 정의를 위해)
  • HTTP 서버는 아니지만 실제로는 RFC 호환이 아니며 일반적으로 필요한 기본 기능을 지원하지 않는 영광스러운 ServerSocket 예제입니다.

그래서 ... 나는 JLHTTP-자바 경량 HTTP 서버 를 쓰기 시작했다 .

하나의 (아주 긴 경우) 소스 파일 또는 종속성이없는 ~ 50K jar (~ 35K stripped)으로 모든 프로젝트에 포함 할 수 있습니다. RFC를 준수하기 위해 노력하고 있으며 부풀림을 최소화하면서 광범위한 문서와 많은 유용한 기능을 포함합니다.

가상 호스트, 디스크에서 파일 제공, 표준 mime.types 파일을 통한 MIME 유형 맵핑, 디렉토리 색인 생성, 환영 파일, 모든 HTTP 메소드 지원, 조건부 ETag 및 If- * 헤더 지원, 청크 분할 전송 인코딩, gzip / deflate 압축, 기본 HTTPS (JVM에서 제공), 부분 컨텐츠 (다운로드 계속), 파일 업로드를위한 다중 파트 / 양식-데이터 처리, API 또는 주석을 통한 다중 컨텍스트 핸들러, 매개 변수 구문 분석 (쿼리 문자열 또는 x-www-form-urlencoded 바디) 등

다른 사람들이 유용하다고 생각하기를 바랍니다 :-)


주요 방법은 기본 사용법의 좋은 예이며 FAQ 는 많은 세부 사항으로 들어갑니다. 기존 문서 개선에 대한 제안이 있으면 언제든지 저에게 직접 연락하십시오!
amichair



8

단 몇 줄의 코드로 JDK와 서블릿 API를 사용하여 J2EE 서블릿에 대한 기본 지원을 제공하는 httpserver를 작성할 수 있습니다.

나는 다른 경량 컨테이너보다 훨씬 빨리 시작하기 때문에 단위 테스트 서블릿에 매우 유용하다는 것을 알았습니다 (제조에는 부두를 사용합니다).

가장 가벼운 httpserver는 서블릿을 지원하지 않지만, 우리는 그것들을 필요로하므로 공유 할 것이라고 생각했습니다.

아래 예제는 기본 서블릿 지원 또는 아직 구현되지 않은 항목에 대한 throw 및 UnsupportedOperationException을 제공합니다. 기본 http 지원을 위해 com.sun.net.httpserver.HttpServer를 사용합니다.

import java.io.*;
import java.lang.reflect.*;
import java.net.InetSocketAddress;
import java.util.*;

import javax.servlet.*;
import javax.servlet.http.*;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

@SuppressWarnings("deprecation")
public class VerySimpleServletHttpServer {
    HttpServer server;
    private String contextPath;
    private HttpHandler httpHandler;

    public VerySimpleServletHttpServer(String contextPath, HttpServlet servlet) {
        this.contextPath = contextPath;
        httpHandler = new HttpHandlerWithServletSupport(servlet);
    }

    public void start(int port) throws IOException {
        InetSocketAddress inetSocketAddress = new InetSocketAddress(port);
        server = HttpServer.create(inetSocketAddress, 0);
        server.createContext(contextPath, httpHandler);
        server.setExecutor(null);
        server.start();
    }

    public void stop(int secondsDelay) {
        server.stop(secondsDelay);
    }

    public int getServerPort() {
        return server.getAddress().getPort();
    }

}

final class HttpHandlerWithServletSupport implements HttpHandler {

    private HttpServlet servlet;

    private final class RequestWrapper extends HttpServletRequestWrapper {
        private final HttpExchange ex;
        private final Map<String, String[]> postData;
        private final ServletInputStream is;
        private final Map<String, Object> attributes = new HashMap<>();

        private RequestWrapper(HttpServletRequest request, HttpExchange ex, Map<String, String[]> postData, ServletInputStream is) {
            super(request);
            this.ex = ex;
            this.postData = postData;
            this.is = is;
        }

        @Override
        public String getHeader(String name) {
            return ex.getRequestHeaders().getFirst(name);
        }

        @Override
        public Enumeration<String> getHeaders(String name) {
            return new Vector<String>(ex.getRequestHeaders().get(name)).elements();
        }

        @Override
        public Enumeration<String> getHeaderNames() {
            return new Vector<String>(ex.getRequestHeaders().keySet()).elements();
        }

        @Override
        public Object getAttribute(String name) {
            return attributes.get(name);
        }

        @Override
        public void setAttribute(String name, Object o) {
            this.attributes.put(name, o);
        }

        @Override
        public Enumeration<String> getAttributeNames() {
            return new Vector<String>(attributes.keySet()).elements();
        }

        @Override
        public String getMethod() {
            return ex.getRequestMethod();
        }

        @Override
        public ServletInputStream getInputStream() throws IOException {
            return is;
        }

        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(getInputStream()));
        }

        @Override
        public String getPathInfo() {
            return ex.getRequestURI().getPath();
        }

        @Override
        public String getParameter(String name) {
            String[] arr = postData.get(name);
            return arr != null ? (arr.length > 1 ? Arrays.toString(arr) : arr[0]) : null;
        }

        @Override
        public Map<String, String[]> getParameterMap() {
            return postData;
        }

        @Override
        public Enumeration<String> getParameterNames() {
            return new Vector<String>(postData.keySet()).elements();
        }
    }

    private final class ResponseWrapper extends HttpServletResponseWrapper {
        final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        final ServletOutputStream servletOutputStream = new ServletOutputStream() {

            @Override
            public void write(int b) throws IOException {
                outputStream.write(b);
            }
        };

        private final HttpExchange ex;
        private final PrintWriter printWriter;
        private int status = HttpServletResponse.SC_OK;

        private ResponseWrapper(HttpServletResponse response, HttpExchange ex) {
            super(response);
            this.ex = ex;
            printWriter = new PrintWriter(servletOutputStream);
        }

        @Override
        public void setContentType(String type) {
            ex.getResponseHeaders().add("Content-Type", type);
        }

        @Override
        public void setHeader(String name, String value) {
            ex.getResponseHeaders().add(name, value);
        }

        @Override
        public javax.servlet.ServletOutputStream getOutputStream() throws IOException {
            return servletOutputStream;
        }

        @Override
        public void setContentLength(int len) {
            ex.getResponseHeaders().add("Content-Length", len + "");
        }

        @Override
        public void setStatus(int status) {
            this.status = status;
        }

        @Override
        public void sendError(int sc, String msg) throws IOException {
            this.status = sc;
            if (msg != null) {
                printWriter.write(msg);
            }
        }

        @Override
        public void sendError(int sc) throws IOException {
            sendError(sc, null);
        }

        @Override
        public PrintWriter getWriter() throws IOException {
            return printWriter;
        }

        public void complete() throws IOException {
            try {
                printWriter.flush();
                ex.sendResponseHeaders(status, outputStream.size());
                if (outputStream.size() > 0) {
                    ex.getResponseBody().write(outputStream.toByteArray());
                }
                ex.getResponseBody().flush();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                ex.close();
            }
        }
    }

    public HttpHandlerWithServletSupport(HttpServlet servlet) {
        this.servlet = servlet;
    }

    @SuppressWarnings("deprecation")
    @Override
    public void handle(final HttpExchange ex) throws IOException {
        byte[] inBytes = getBytes(ex.getRequestBody());
        ex.getRequestBody().close();
        final ByteArrayInputStream newInput = new ByteArrayInputStream(inBytes);
        final ServletInputStream is = new ServletInputStream() {

            @Override
            public int read() throws IOException {
                return newInput.read();
            }
        };

        Map<String, String[]> parsePostData = new HashMap<>();

        try {
            parsePostData.putAll(HttpUtils.parseQueryString(ex.getRequestURI().getQuery()));

            // check if any postdata to parse
            parsePostData.putAll(HttpUtils.parsePostData(inBytes.length, is));
        } catch (IllegalArgumentException e) {
            // no postData - just reset inputstream
            newInput.reset();
        }
        final Map<String, String[]> postData = parsePostData;

        RequestWrapper req = new RequestWrapper(createUnimplementAdapter(HttpServletRequest.class), ex, postData, is);

        ResponseWrapper resp = new ResponseWrapper(createUnimplementAdapter(HttpServletResponse.class), ex);

        try {
            servlet.service(req, resp);
            resp.complete();
        } catch (ServletException e) {
            throw new IOException(e);
        }
    }

    private static byte[] getBytes(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        while (true) {
            int r = in.read(buffer);
            if (r == -1)
                break;
            out.write(buffer, 0, r);
        }
        return out.toByteArray();
    }

    @SuppressWarnings("unchecked")
    private static <T> T createUnimplementAdapter(Class<T> httpServletApi) {
        class UnimplementedHandler implements InvocationHandler {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                throw new UnsupportedOperationException("Not implemented: " + method + ", args=" + Arrays.toString(args));
            }
        }

        return (T) Proxy.newProxyInstance(UnimplementedHandler.class.getClassLoader(),
                new Class<?>[] { httpServletApi },
                new UnimplementedHandler());
    }
}

이것은 ServletOutputStream 및 ServletInputStream에 대한 일부 메소드가 누락되었습니다
HomeIsWhereThePcIs

서블릿 API의 최신 버전은 3.0 이하입니다. 필요에 따라 누락 된 메타도를 예제에 추가하십시오
f.carlsen

6

특히 서블릿 기능이 필요하지 않고 단순히 요청 / 응답 객체에 액세스하는 경우 Simple을 조사하는 것이 좋습니다 . REST가 필요한 경우 Jersey를 맨 위에 놓을 수 있으며 HTML 또는 이와 유사한 것을 출력 해야하는 경우 Freemarker가 있습니다. 나는이 조합으로 할 수있는 일을 정말 좋아하며 배울 API가 거의 없습니다.


+1. 나는 Simple의 아이디어를 좋아한다. 그러나 Mamba가 Simple에서 "embeddable"기능을 제거하기 때문에 HTTPS를 사용하려고 할 때 문제가 발생합니다.
ThreaT

6

이 코드는 우리 코드보다 낫습니다. javax.servelet.jarorg.mortbay.jetty.jar 두 개의 라이브러리 만 추가하면됩니다 .

부두

package jetty;

import java.util.logging.Level;
import java.util.logging.Logger;
import org.mortbay.http.SocketListener;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.ServletHttpContext;

public class Jetty {

    public static void main(String[] args) {
        try {
            Server server = new Server();
            SocketListener listener = new SocketListener();      

            System.out.println("Max Thread :" + listener.getMaxThreads() + " Min Thread :" + listener.getMinThreads());

            listener.setHost("localhost");
            listener.setPort(8070);
            listener.setMinThreads(5);
            listener.setMaxThreads(250);
            server.addListener(listener);            

            ServletHttpContext context = (ServletHttpContext) server.getContext("/");
            context.addServlet("/MO", "jetty.HelloWorldServlet");

            server.start();
            server.join();

        /*//We will create our server running at http://localhost:8070
        Server server = new Server();
        server.addListener(":8070");

        //We will deploy our servlet to the server at the path '/'
        //it will be available at http://localhost:8070
        ServletHttpContext context = (ServletHttpContext) server.getContext("/");
        context.addServlet("/MO", "jetty.HelloWorldServlet");

        server.start();
        */

        } catch (Exception ex) {
            Logger.getLogger(Jetty.class.getName()).log(Level.SEVERE, null, ex);
        }

    }
} 

서블릿 클래스 :

package jetty;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloWorldServlet extends HttpServlet
{
    @Override
    protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException
    {
        String appid = httpServletRequest.getParameter("appid");
        String conta = httpServletRequest.getParameter("conta");

        System.out.println("Appid : "+appid);
        System.out.println("Conta : "+conta);

        httpServletResponse.setContentType("text/plain");
        PrintWriter out = httpServletResponse.getWriter();
        out.println("Hello World!");
        out.close();
    }
}

2
이 질문은 순수한 Java SE 솔루션을 요구합니다. 부두가 Java EE API를 구현하고 있음을 알 수 있습니다.
Sridhar

Jetty는 표준 Java SE를 사용하여 완벽하게 실행되므로 요구 사항에 맞습니다. 그것은 구현하는 자바 EE의 API의 일부, 그것은하지 않습니다 필요 를. 차이가 있습니다.
David Tonhofer

1
자격이 없습니다. "그냥 자바 SE API를 사용하여" . *.Servlet.jar그리고 *.jetty.jar분명히 자바 SE의 일부가 아닙니다.
icza

부두를 설치해야합니까? 아니면 두 항아리를 제외 하고이 파일을 실행할 수 있습니까?
Paul Preibisch


4

위의 모든 것은 단일 메인 스레드 요청 처리기에 대한 세부 정보에 대한 답변입니다.

환경:

 server.setExecutor(java.util.concurrent.Executors.newCachedThreadPool());

실행기 서비스를 사용하여 여러 스레드를 통해 여러 요청을 처리 할 수 ​​있습니다.

따라서 종료 코드는 다음과 같습니다.

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
public class App {
    public static void main(String[] args) throws Exception {
        HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
        server.createContext("/test", new MyHandler());
        //Thread control is given to executor service.
        server.setExecutor(java.util.concurrent.Executors.newCachedThreadPool());
        server.start();
    }
    static class MyHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange t) throws IOException {
            String response = "This is the response";
            long threadId = Thread.currentThread().getId();
            System.out.println("I am thread " + threadId );
            response = response + "Thread Id = "+threadId;
            t.sendResponseHeaders(200, response.length());
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }
}

3

간단한 결제 . 상당히 다양한 내장 작업을 지원하는 매우 간단한 내장형 서버입니다. 나는 특히 스레딩 모델을 좋아합니다 ..

놀랄 만한!



2

Apache Commons HttpCore 프로젝트는 어떻습니까?

웹 사이트에서 : HttpCore 목표

  • 가장 기본적인 HTTP 전송 측면의 구현
  • 좋은 성능과 API의 명확성 및 표현성의 균형
  • 작은 (예측 가능한) 메모리 공간
  • 자체 포함 라이브러리 (JRE 이외의 외부 종속성 없음)

아마도 너무 낮은 수준 일 것입니다. 청크, 인코딩 등과 같은 모든 개념을 스스로 다루고 싶지 않다면 적어도 서블릿 API 레벨에서 코드를 호출하는 솔루션을 목표로 삼아야합니다. 그래도 재미있을 수 있습니다.
David Tonhofer

2

이것을 시도하십시오 https://github.com/devashish234073/Java-Socket-Http-Server/blob/master/README.md

이 API는 소켓을 사용하여 HTTP 서버를 작성합니다.

  1. 브라우저에서 텍스트로 요청을받습니다.
  2. URL 정보, 메소드, 속성 등을 검색하기 위해 구문 분석합니다.
  3. 정의 된 URL 매핑을 사용하여 동적 응답을 만듭니다.
  4. 브라우저에 응답을 보냅니다.

예를 들어 다음은 Response.java클래스 의 생성자 가 원시 응답을 http 응답으로 변환하는 방법입니다 .

public Response(String resp){
    Date date = new Date();
    String start = "HTTP/1.1 200 OK\r\n";
    String header = "Date: "+date.toString()+"\r\n";
    header+= "Content-Type: text/html\r\n";
    header+= "Content-length: "+resp.length()+"\r\n";
    header+="\r\n";
    this.resp=start+header+resp;
}

1

매우 간단한 임베디드 Jetty Java 서버를 작성할 수 있습니다 .

내장 된 Jetty는 외부 Jetty 서버에 응용 프로그램을 배포하는 대신 서버 (Jetty)가 응용 프로그램과 함께 제공되었음을 의미합니다.

따라서 내장되지 않은 접근 방식에서 일부 외부 서버 ( Tomcat / Jetty 등)에 내장 된 WAR 파일에 내장 된 WAR 파일이 내장 된 Jetty의 경우 webapp를 작성하고 동일한 코드베이스에서 jetty 서버를 인스턴스화합니다.

임베디드 Jetty Java 서버의 예는 git clone 을 사용하고 다음을 사용할 수 있습니다. https://github.com/stas-slu/embedded-jetty-java-server-example

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.