einfacher HTTP-Server in Java, der nur die Java SE-API verwendet

333

Gibt es eine Möglichkeit, einen sehr einfachen HTTP-Server (der nur GET / POST unterstützt) in Java nur mit der Java SE-API zu erstellen, ohne Code zu schreiben, um HTTP-Anforderungen manuell zu analysieren und HTTP-Antworten manuell zu formatieren? Die Java SE-API kapselt die HTTP-Client-Funktionalität in HttpURLConnection gut, aber gibt es ein Analogon für die HTTP-Server-Funktionalität?

Um ganz klar zu sein, das Problem, das ich mit vielen ServerSocket-Beispielen habe, die ich online gesehen habe, ist, dass sie ihre eigenen Anforderungsanalyse- / Antwortformatierungen und Fehlerbehandlungen durchführen, was mühsam, fehleranfällig und wahrscheinlich nicht umfassend ist. und ich versuche es aus diesen Gründen zu vermeiden.

Als Beispiel für die manuelle HTTP-Manipulation, die ich vermeiden möchte:

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

Frager
quelle
3
Ähm ... die kurze Antwort ist nein. Wenn Sie etwas möchten, das das Posten und Abrufen von Anforderungen behandelt, ohne die http-Header manuell zu schreiben, können Sie Servlets verwenden. Aber das ist Java ee. Wenn Sie so etwas nicht verwenden möchten, sind Sockets und manuelles Parsen die einzige andere Option, die mir bekannt ist.
Matt Phillips
3
Ich weiß, dass dies nicht im Sinne von SO ist, aber ich möchte Sie dringend bitten, Ihre Abneigung gegen Java EE-APIs zu überdenken. Wie einige der Antworten bereits erwähnt haben, gibt es einige sehr einfache Implementierungen wie Jetty, mit denen Sie einen Webserver in Ihre eigenständige Anwendung einbetten können, während Sie weiterhin die Servlet-API nutzen. Wenn Sie die Java EE-API aus irgendeinem Grund absolut nicht verwenden können, ignorieren Sie bitte meinen Kommentar :-)
Chris Thompson
1
"Servlets" sind nicht wirklich "Java EE". Sie sind nur eine Möglichkeit, Plugins zu schreiben, die von der umgebenden Anwendung als Reaktion auf Nachrichtenaktivitäten aufgerufen werden können (heutzutage im Allgemeinen HTTP-Anforderungen). Die Bereitstellung einer Servlet-Hosting-Umgebung "nur mit der Java SE-API" ist genau das, was Jetty und Tomcat tun. Natürlich möchten Sie möglicherweise unerwünschte Komplexität beseitigen , müssen sich dann aber möglicherweise für eine Teilmenge der zulässigen Attribute und Konfigurationen des GET / POST entscheiden. Es lohnt sich jedoch oft nicht, außer bei speziellen Sicherheits- / Embedded-Problemen.
David Tonhofer
1
Es kann sich lohnen, diese Liste der http-Server durchzugehen, bevor Sie eine Entscheidung treffen. java-source.net/open-source/web-servers
Bedrohung

Antworten:

469

Seit Java SE 6 gibt es in Sun Oracle JRE einen integrierten HTTP-Server . Die com.sun.net.httpserverPaketzusammenfassung beschreibt die beteiligten Klassen und enthält Beispiele.

Hier ist ein Kickoff-Beispiel, das aus ihren Dokumenten kopiert wurde (für alle Leute, die dennoch versuchen, es zu bearbeiten, da es sich um einen hässlichen Code handelt, bitte nicht, dies ist eine Kopierpaste, nicht meine, außerdem sollten Sie Zitate niemals bearbeiten, es sei denn, sie haben sich geändert in der Originalquelle). Sie können es einfach auf Java 6+ kopieren und einfügen.

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();
        }
    }

}

Es sollte angemerkt werden, dass der response.length()Teil in ihrem Beispiel schlecht ist, es hätte sein sollen response.getBytes().length. Auch dann ist diegetBytes() Methode den Zeichensatz explizit angeben, den Sie dann im Antwortheader angeben. Leider ist es, obwohl es für Anfänger falsch ist, immerhin nur ein einfaches Kickoff-Beispiel.

Führen Sie es aus und gehen Sie zu http: // localhost: 8000 / test. Die folgende Antwort wird angezeigt:

Dies ist die Antwort


com.sun.*Beachten Sie bei der Verwendung von Klassen, dass dies entgegen der Meinung einiger Entwickler in den bekannten FAQs, warum Entwickler keine Programme schreiben sollten, die "Sun" -Pakete aufrufen , absolut nicht verboten ist . Diese FAQ betrifft das sun.*Paket (z. B. sun.misc.BASE64Encoder) für die interne Verwendung durch die Oracle-JRE (wodurch Ihre Anwendung beendet wird, wenn Sie sie auf einer anderen JRE ausführen) und nicht das com.sun.*Paket. Sun / Oracle entwickelt wie jedes andere Unternehmen wie Apache usw. auch nur Software auf der Java SE-API. Die Verwendung von com.sun.*Klassen wird nur empfohlen (aber nicht verboten), wenn es sich um eine Implementierung einer bestimmten Java-API handelt, z. B. GlassFish (Java EE impl), Mojarra (JSF impl), Jersey (JAX-RS impl) usw.

BalusC
quelle
19
@Waldheinz: wie als @Software Sie verwirren sun.*mit com.sun.*. Sehen Sie beispielsweise eine Dokumentation der sun.*API? Schauen Sie hier: java.sun.com/products/jdk/faq/faq-sun-packages.html Erzählt es etwas darüber com.sun.*? Das com.sun.*wird nur für ihre eigene öffentliche Software verwendet, die nicht Teil der Java-API ist. Wie jedes andere Unternehmen entwickeln sie auch Software über die Java-API.
BalusC
4
Ich denke, dies ist ein sehr schöner http-Server für Integrationstestfälle. danke für den Tipp!
Andreas Petersson
13
Wenn Sie Eclipse verwenden und eine Fehlermeldung wie "Zugriffsbeschränkung: Der Typ HttpExchange ist aufgrund der Einschränkung der erforderlichen Bibliothek nicht verfügbar ..." angezeigt wird , erfahren Sie unter stackoverflow.com/a/10642163 , wie Sie diese Zugriffsprüfung deaktivieren.
Samuli Pahaoja
13
FWIW dies ist auch in OpenJDK vorhanden.
Jason C
6
Die hier genannten Klassen sind @jdk.Exportedim OpenJDK-Quellcode markiert. Dies bedeutet, dass die API als öffentlich betrachtet wird und unter Java 9 verfügbar ist (einige andere com.sun.*Pakete sind aufgrund von Project Jigsaw nicht mehr verfügbar).
Jules
42

Schauen Sie sich NanoHttpd an

"NanoHTTPD ist ein leichter HTTP-Server, der zum Einbetten in andere Anwendungen entwickelt wurde und unter einer modifizierten BSD-Lizenz veröffentlicht wurde.

Es wird bei Github entwickelt und verwendet Apache Maven für Builds und Unit-Tests. "

letronje
quelle
4
Eine Warnung: Es ist wahrscheinlich, dass NanoHTTPD keinen Schutz gegen Angriffe beim Gehen mit Bäumen bietet. Sie sollten dies überprüfen, wenn es an einer öffentlichen Adresse bereitgestellt wird. Damit meine ich Angriffe, bei denen eine Anforderung wie GET /../../blahblah http/1.1ausgegeben wird und der Server über das Stammverzeichnis der Website in das Systemdateiland gelangt und Dateien bereitstellt, mit denen das System kompromittiert oder remote angegriffen werden kann, z. B. eine Kennwortdatei.
Lawrence Dol
7
Das scheint behoben zu sein. Die aktuelle Version generiert eine 403 if (uri.startsWith ("..") || uri.endsWith ("..") || uri.indexOf ("../")> = 0).
Lena Schimmel
5
Ich verstehe nicht, wie dies eine Antwort auf diese Frage ist.
Kimathie
28

Die Lösung com.sun.net.httpserver ist nicht über JREs portierbar. Es ist besser, die offizielle Webservices-API in javax.xml.ws zu verwenden, um einen minimalen HTTP-Server zu booten ...

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)

EDIT: das funktioniert tatsächlich! Der obige Code sieht aus wie Groovy oder so. Hier ist eine Übersetzung nach Java, die ich getestet habe:

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);
    }
}
gruenewa
quelle
1
+1 für tragbar sein. Schade, dass Sie den Antwortinhaltstyp nicht so einstellen können, wie er ist text/xml.
icza
1
Ich denke, Sie könnten <code> class Server implementieren Provider <DataSource> {</ code> ... und dann den Inhaltstyp in der <code> getContentType () </ code> -Methode der DataSource angeben. Darüber hinaus können Sie auch den WebServiceContext einfügen: <code> @Resource WebServiceContext ctx; </ code>, um andere Header festzulegen und Anforderungsparameter zu lesen. Leider funktioniert das Festlegen des Inhaltstyps über WebServiceContext nicht.
Gruenewa
4
Können Sie bitte erklären, warum com.sun.net.HttpServer nicht über JREs portierbar ist?
Javabeangrinder
3
Nein, das glaube ich nicht. Es funktioniert nicht mit der Java-Implementierung von IBM und möglicherweise auch mit anderen. Und selbst wenn es jetzt funktioniert, dürfen sich interne APIs ändern. Warum nicht einfach die offizielle API verwenden?
Gruenewa
1
Dieser Link: docs.oracle.com/javase/9/docs/api/java.xml.ws-summary.html besagt, dass das Modul java.xml.ws seit Java 9 veraltet ist.
Erel Segal-Halevi
22

Ich mag diese Frage, weil dies ein Bereich ist, in dem es kontinuierliche Innovationen gibt und immer ein leichter Server erforderlich ist, insbesondere wenn es um eingebettete Server in kleinen (er) Geräten geht. Ich denke, die Antworten fallen in zwei große Gruppen.

  1. Thin-Server : Server-up statischer Inhalt mit minimaler Verarbeitung, Kontext- oder Sitzungsverarbeitung.
  2. Kleiner Server : Angeblich hat ein Server viele httpD-ähnliche Serverqualitäten mit einem so geringen Platzbedarf, wie Sie nur können.

Während ich HTTP-Bibliotheken wie Jetty , Apache Http Components , Netty und andere eher als rohe HTTP-Verarbeitungsfunktionen betrachten könnte. Die Kennzeichnung ist sehr subjektiv und hängt von der Art der Dinge ab, die Sie für kleine Websites geliefert haben. Ich mache diese Unterscheidung im Geiste der Frage, insbesondere der Bemerkung über ...

  • "... ohne Code zu schreiben, um HTTP-Anforderungen manuell zu analysieren und HTTP-Antworten manuell zu formatieren ..."

Mit diesen Rohwerkzeugen können Sie dies tun (wie in anderen Antworten beschrieben). Sie eignen sich nicht wirklich für einen sofort einsatzbereiten Stil, um einen leichten, eingebetteten oder Mini-Server herzustellen. Ein Mini-Server bietet Ihnen ähnliche Funktionen wie ein voll funktionsfähiger Webserver (z. B. Tomcat ) ohne Schnickschnack, mit geringem Volumen und 99% der Zeit mit guter Leistung. Ein Thin-Server scheint der ursprünglichen Formulierung nur ein bisschen mehr als roh zu sein, vielleicht mit einer eingeschränkten Teilmengenfunktionalität, die ausreicht, um Sie in 90% der Fälle gut aussehen zu lassen. Meine Vorstellung von roh würde mich 75% - 89% der Zeit ohne zusätzliches Design und Codierung gut aussehen lassen. Ich denke, wenn Sie das Niveau der WAR-Dateien erreichen, haben wir das "kleine" für Bonsi-Server belassen, das aussieht wie alles, was ein großer Server kleiner macht.

Thin-Server-Optionen

Mini-Server-Optionen:

  • Spark Java ... Gute Dinge sind mit vielen Hilfskonstrukten wie Filtern, Vorlagen usw. möglich.
  • MadVoc ... will Bonsai sein und könnte es auch sein ;-)

Unter anderem würde ich Authentifizierung, Validierung, Internationalisierung und die Verwendung von FreeMaker oder einem anderen Vorlagentool zum Rendern der Seitenausgabe einschließen . Andernfalls sieht die Verwaltung der HTML-Bearbeitung und -Parametrisierung wahrscheinlich so aus, als würde die Arbeit mit HTTP wie Nullen und Kreuze aussehen. Natürlich hängt alles davon ab, wie flexibel Sie sein müssen. Wenn es sich um eine menügesteuerte Faxmaschine handelt, kann dies sehr einfach sein. Je mehr Interaktionen, desto " dicker " muss Ihr Framework sein. Gute Frage, viel Glück!

werden
quelle
21

Werfen Sie einen Blick auf die „Jetty“ Webserver Jetty . Hervorragende Open Source-Software, die alle Ihre Anforderungen zu erfüllen scheint.

Wenn Sie darauf bestehen, Ihre eigenen zu rollen, schauen Sie sich die Klasse "httpMessage" an.

James Anderson
quelle
Ich denke, Jetty API hängt vom Servlet ab.
unwiderlegbar
4
@Irreputable: Nein, Jetty ist ein hochmodularer Webserver, dessen optionales Modul einen Servlet-Container enthält.
Lawrence Dol
"Ist es ein Analogon für die Serverfunktionalität?" - Ja, es ist die "Servlet" -API. Der Servlet-Container ruft Ihre Klasse auf, nachdem er die Header, Cookies usw. analysiert hat
James Anderson
1
Nur zur Veranschaulichung - Jetty kommt mit einer eigenen Implementierung der Servlet-API und funktioniert gut mit Java SE
James Anderson
4
Jetty ist zu groß und hat zu viel Lernaufwand, bevor eine tatsächliche Produktionsnutzung möglich wird.
Bedrohung
18

Es war einmal, als ich nach etwas Ähnlichem suchte - einem leichten, aber voll funktionsfähigen HTTP-Server, den ich einfach einbetten und anpassen konnte. Ich habe zwei Arten möglicher Lösungen gefunden:

  • Volle Server, die nicht so leicht oder einfach sind (für eine extreme Definition von Leichtgewicht).
  • Wirklich leichte Server, die keine HTTP-Server sind, aber verherrlichte ServerSocket-Beispiele, die nicht einmal remote RFC-kompatibel sind und nicht die häufig benötigten Grundfunktionen unterstützen.

Also ... machte ich mich daran, JLHTTP - The Java Lightweight HTTP Server zu schreiben .

Sie können es in jedes Projekt als einzelne (wenn auch ziemlich lange) Quelldatei oder als ~ 50K-JAR (~ 35K entfernt) ohne Abhängigkeiten einbetten. Es ist bestrebt, RFC-konform zu sein und enthält eine umfangreiche Dokumentation sowie viele nützliche Funktionen, während das Aufblähen auf ein Minimum beschränkt bleibt.

Zu den Funktionen gehören: virtuelle Hosts, Dateien, die von der Festplatte bereitgestellt werden, MIME-Typzuordnungen über die Standarddatei mime.types, Verzeichnisindexgenerierung, Begrüßungsdateien, Unterstützung für alle HTTP-Methoden, Unterstützung für bedingte ETags und If- * -Header, Chunked-Transfer-Codierung, gzip / deflate Komprimierung, grundlegendes HTTPS (wie von der JVM bereitgestellt), Teilinhalt (Fortsetzung des Downloads), mehrteilige / Formulardatenverarbeitung für Datei-Uploads, mehrere Kontext-Handler über API oder Anmerkungen, Parameteranalyse (Abfragezeichenfolge oder x-www-form-urlencoded) Körper) usw.

Ich hoffe andere finden es nützlich :-)

Amichair
quelle
Die Hauptmethode ist ein gutes Beispiel für die grundlegende Verwendung, und in den häufig gestellten Fragen werden viele Details erläutert. Wenn Sie Vorschläge zur Verbesserung der vorhandenen Dokumente haben, können Sie mich gerne direkt kontaktieren!
Amichair
10

Spark ist am einfachsten. Hier ist eine Kurzanleitung: http://sparkjava.com/

Laercio Metzner
quelle
8

Es ist möglich, einen http-Server zu erstellen, der grundlegende Unterstützung für J2EE-Servlets mit nur dem JDK und der Servlet-API in nur wenigen Codezeilen bietet.

Ich fand dies sehr nützlich für Unit-Test-Servlets, da es viel schneller startet als andere leichte Container (wir verwenden Steg für die Produktion).

Die meisten sehr leichten http-Server bieten keine Unterstützung für Servlets, aber wir brauchen sie, also dachte ich, ich würde sie teilen.

Das folgende Beispiel bietet grundlegende Servlet-Unterstützung oder Throws und UnsupportedOperationException für noch nicht implementierte Inhalte. Es verwendet den com.sun.net.httpserver.HttpServer für die grundlegende http-Unterstützung.

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());
    }
}
f.carlsen
quelle
Dies fehlt einige Methoden auf ServletOutputStream und ServletInputStream
HomeIsWhereThePcIs
neuere Version der Servlet-API, oben passt 3.0 und darunter. Fügen Sie einfach fehlende Methdos nach Bedarf in das Beispiel ein
f.carlsen
6

Ich kann dringend empfehlen, sich mit Simple zu befassen, insbesondere wenn Sie keine Servlet-Funktionen benötigen, sondern einfach auf die Anforderungs- / Antwortobjekte zugreifen. Wenn Sie REST benötigen, können Sie Jersey darüber legen. Wenn Sie HTML oder ähnliches ausgeben müssen, gibt es Freemarker. Ich finde es wirklich toll, was man mit dieser Kombination machen kann, und es gibt relativ wenig API zu lernen.

Waldheinz
quelle
+1. Ich mag die Ideen hinter Simple. Beim Versuch, HTTPS zu verwenden, treten jedoch Probleme auf, da Mamba die Funktion "Einbettbar" von Simple entfernt.
Bedrohung
6

Dieser Code ist besser als unser Code. Sie müssen nur zwei Bibliotheken hinzufügen: javax.servelet.jar und org.mortbay.jetty.jar .

Klassensteg:

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);
        }

    }
} 

Servlet-Klasse:

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();
    }
}
Leandro
quelle
2
Die Frage fragt nach einer rein Java SE-Lösung. Sie werden feststellen, dass Jetty die Java EE-API implementiert.
Sridhar
Jetty läuft perfekt mit Standard-Java SE und entspricht daher den Anforderungen. Es implementiert Teile der Java EE-API und benötigt sie nicht. Da ist ein Unterschied.
David Tonhofer
1
Dies ist nicht qualifiziert. "Nur mit der Java SE API" . *.Servlet.jarund *.jetty.jarsind offensichtlich nicht Teil von Java SE.
icza
Muss ich einen Steg einrichten? oder kann ich diese beiden Gläser einfach ausschließen und diese Datei ausführen?
Paul Preibisch
4

Alle oben genannten Antworten enthalten Details zum Anforderungshandler mit einem Haupt-Thread.

Rahmen:

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

Ermöglicht die Bearbeitung mehrerer Anforderungen über mehrere Threads mithilfe des Executor-Dienstes.

Der Endcode lautet also wie folgt:

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();
        }
    }
}
Balu Mallisetty
quelle
3

Kasse Einfach . Es ist ein ziemlich einfacher einbettbarer Server mit integrierter Unterstützung für eine Vielzahl von Vorgängen. Ich liebe besonders das Einfädelmodell.

Tolle!

Olu Smith
quelle
2

Wie wäre es mit Apache Commons HttpCore- Projekt?

Von der Website: ... HttpCore-Ziele

  • Implementierung der grundlegendsten HTTP-Transportaspekte
  • Balance zwischen guter Leistung und der Klarheit und Ausdruckskraft von API
  • Kleiner (vorhersehbarer) Speicherbedarf
  • Eigenständige Bibliothek (keine externen Abhängigkeiten über JRE hinaus)
Iqbal
quelle
Das ist wahrscheinlich zu niedrig. Man sollte zumindest eine Lösung anstreben, die Ihren Code auf Servlet-API-Ebene aufruft, es sei denn, man möchte sich selbst mit allen Konzepten wie Chunking, Codierung usw. befassen. Es kann aber Spaß machen.
David Tonhofer
2

Versuchen Sie dies unter https://github.com/devashish234073/Java-Socket-Http-Server/blob/master/README.md

Diese API hat einen HTTP-Server mithilfe von Sockets erstellt.

  1. Es erhält eine Anfrage vom Browser als Text
  2. Analysiert es, um URL-Informationen, Methoden, Attribute usw. abzurufen.
  3. Erstellt eine dynamische Antwort mithilfe der definierten URL-Zuordnung
  4. Sendet die Antwort an den Browser.

So Response.javakonvertiert der Konstruktor in der Klasse beispielsweise eine unformatierte Antwort in eine http-Antwort:

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;
}
Devashish Priyadarshi
quelle
1

Sie können einen ziemlich einfachen eingebetteten Jetty Java-Server schreiben .

Embedded Jetty bedeutet, dass der Server (Jetty) zusammen mit der Anwendung ausgeliefert wird, anstatt die Anwendung auf einem externen Jetty-Server bereitzustellen.

Wenn Ihre Webanwendung im nicht eingebetteten Ansatz in eine WAR-Datei integriert ist, die auf einem externen Server ( Tomcat / Jetty / etc) bereitgestellt wurde, schreiben Sie in Embedded Jetty die Webanwendung und instanziieren den Jetty-Server in derselben Codebasis.

Ein Beispiel für einen eingebetteten Jetty Java-Server, den Sie klonen und verwenden können: https://github.com/stas-slu/embedded-jetty-java-server-example

Johnny
quelle