prosty serwer HTTP w Javie wykorzystujący tylko Java SE API

333

Czy istnieje sposób na stworzenie bardzo podstawowego serwera HTTP (obsługującego tylko GET / POST) w Javie przy użyciu tylko API Java SE, bez pisania kodu do ręcznej analizy żądań HTTP i ręcznego formatowania odpowiedzi HTTP? Interfejs API Java SE ładnie zawiera funkcjonalność klienta HTTP w HttpURLConnection, ale czy istnieje analogia do funkcjonalności serwera HTTP?

Dla jasności, problem, który mam z wieloma przykładami ServerSocket, które widziałem online, polega na tym, że same analizują żądania / formatują odpowiedzi i obsługują błędy, co jest żmudne, podatne na błędy i mało prawdopodobne, aby było wyczerpujące, i staram się tego unikać z tych powodów.

Jako przykład ręcznej manipulacji HTTP, której próbuję uniknąć:

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

pytający
źródło
3
Umm ... krótka odpowiedź brzmi: nie. Jeśli potrzebujesz czegoś, co obsługuje wysyłanie i odbieranie żądań bez ręcznego pisania nagłówków http, możesz użyć serwletów. Ale to jest java ee. Jeśli nie chcesz używać czegoś takiego, to gniazda i ręczne parsowanie to jedyna inna opcja, o której wiem.
Matt Phillips,
3
Wiem, że to nie jest w duchu SO, ale zachęcam do ponownego rozważenia niechęci do API Java EE. Jak wspomniano w niektórych odpowiedziach, istnieje kilka bardzo prostych implementacji, takich jak Jetty, które umożliwiają osadzenie serwera WWW w autonomicznej aplikacji przy jednoczesnym korzystaniu z apletu apletu. Jeśli z jakiegoś powodu absolutnie nie możesz użyć interfejsu API Java EE, zignoruj ​​mój komentarz :-)
Chris Thompson,
1
„Serwlety” nie są tak naprawdę „Java EE”. Są tylko sposobem na pisanie wtyczek, które mogą być wywoływane przez otaczającą aplikację w odpowiedzi na aktywność wiadomości (obecnie zwykle żądania HTTP). Zapewnienie środowiska hostingowego serwletów „przy użyciu tylko Java SE API” jest dokładnie tym, co robią Jetty i Tomcat. Oczywiście możesz chcieć wyrzucić niechcianą złożoność, ale wtedy możesz zdecydować o podzbiorze dozwolonych atrybutów i konfiguracji GET / POST. Często jednak nie jest tego warte, z wyjątkiem specjalnych problemów związanych z bezpieczeństwem / osadzeniem.
David Tonhofer,
1
Warto podjąć tę listę serwerów HTTP przed podjęciem decyzji. java-source.net/open-source/web-servers
Threat

Odpowiedzi:

469

Od wersji Java SE 6 w Sun Oracle JRE jest wbudowany serwer HTTP . com.sun.net.httpserverZbiorczym przedstawia zaangażowane klasy i zawiera przykłady.

Oto przykładowy początek skopiowany z ich dokumentów (dla wszystkich osób, które próbują go edytować, ponieważ jest to brzydki fragment kodu, proszę nie, to jest wklejanie kopii, a nie moje, ponadto nie należy nigdy edytować cytatów, chyba że uległy zmianie w oryginalnym źródle). Możesz po prostu skopiować i wkleić go w Javie 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();
        }
    }

}

Należy zauważyć, że response.length()część w ich przykładzie jest zła, powinna być response.getBytes().length. Nawet wtedy getBytes()metoda musi jawnie określać zestaw znaków, który następnie określa się w nagłówku odpowiedzi. Niestety, choć mylące dla początkujących, jest to po prostu podstawowy przykład rozpoczęcia.

Wykonaj go i przejdź do http: // localhost: 8000 / test, a zobaczysz następującą odpowiedź:

To jest odpowiedź


Jeśli chodzi o korzystanie z com.sun.*klas, zauważ, że jest to, w przeciwieństwie do tego, co myślą niektórzy programiści, absolutnie nie zabronione przez dobrze znane FAQ Dlaczego programiści nie powinni pisać programów, które nazywają pakiety „słoneczne” . Często zadawane pytania dotyczą sun.*pakietu (np. sun.misc.BASE64Encoder) Do użytku wewnętrznego przez Oracle JRE (który zabiłby twoją aplikację, gdy uruchomisz go na innym JRE), a nie com.sun.*pakietu. Sun / Oracle opracowuje również oprogramowanie oparte na samym interfejsie API Java SE, tak jak każda inna firma, taka jak Apache i tak dalej. Używanie com.sun.*klas jest odradzane (ale nie zabronione) tylko wtedy, gdy dotyczy implementacji niektórych API Java, takich jak GlassFish (Java EE impl), Mojarra (JSF impl), Jersey (JAX-RS impl itp.)

BalusC
źródło
19
@Waldheinz: lubię jak @Software jesteś mylące sun.*z com.sun.*. Czy na przykład widzisz dokumentację sun.*API? Zajrzyj tutaj: java.sun.com/products/jdk/faq/faq-sun-packages.html Czy coś o tym mówi com.sun.*? com.sun.*Jest po prostu wykorzystywane do własnego oprogramowania publicznej, która nie jest częścią Java API. Tworzą także oprogramowanie na bazie Java API, jak każda inna firma.
BalusC,
4
myślę, że jest to bardzo fajny serwer HTTP do użycia w testowych przypadkach integracji. dzięki za podpowiedź!
Andreas Petersson
13
Jeśli używasz Eclipse i pojawia się błąd „Ograniczenie dostępu: typ HttpExchange nie jest dostępny z powodu ograniczenia wymaganej biblioteki ...”, stackoverflow.com/a/10642163 mówi, jak wyłączyć tę kontrolę dostępu.
Samuli Pahaoja,
13
FWIW jest to również obecne w OpenJDK.
Jason C
6
Klasy, o których tu mowa, są oznaczone @jdk.Exportedw kodzie źródłowym OpenJDK, co oznacza, że ​​API jest uważane za publiczne i będzie dostępne w Javie 9 (niektóre inne com.sun.*pakiety staną się niedostępne z powodu Project Jigsaw).
Jules
42

Sprawdź NanoHttpd

„NanoHTTPD to lekki serwer HTTP zaprojektowany do osadzania w innych aplikacjach, wydany na zmodyfikowanej licencji BSD.

Jest rozwijany w Github i używa Apache Maven do kompilacji i testów jednostkowych ”

letronje
źródło
4
Jedna uwaga: jest prawdopodobne, że NanoHTTPD nie ma ochrony przed atakami polegającymi na chodzeniu po drzewach - powinieneś to sprawdzić, czy będzie on działał pod adresem publicznym. Rozumiem przez to ataki, gdy takie żądanie GET /../../blahblah http/1.1jest wysyłane, a serwer przechodzi nad katalogiem głównym witryny do lądowania plików systemowych, udostępniając pliki, których można użyć do złamania lub zdalnego ataku na system, np. Plik hasła.
Lawrence Dol
7
To wydaje się naprawione. Obecna wersja generuje 403 if (uri.startsWith („..”) || uri.endsWith („..”) || uri.indexOf („../”)> = 0).
Lena Schimmel
5
Nie rozumiem, jak to jest odpowiedź na to pytanie.
kimathie,
28

Rozwiązanie com.sun.net.httpserver nie jest przenośne w środowisku JRE. Lepiej jest użyć oficjalnego interfejsu API usług internetowych w pliku javax.xml.ws, aby załadować minimalny serwer 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)

EDYCJA: to faktycznie działa! Powyższy kod wygląda jak Groovy lub coś takiego. Oto tłumaczenie na Javę, które przetestowałem:

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
źródło
1
+1 za bycie przenośnym. Szkoda, że ​​nie można ustawić typu treści odpowiedzi w obecnej postaci text/xml.
icza
1
Myślę, że możesz zrobić <code> serwer klasy implementuje dostawcę <DataSource> {</code> ... a następnie określić Content-Type w metodzie <code> getContentType () </code> DataSource. Ponadto można również wstrzyknąć WebServiceContext: <code> @Resource WebServiceContext ctx; </code>, aby ustawić inne nagłówki i odczytać parametry żądania. Niestety ustawienie typu zawartości za pośrednictwem WebServiceContext nie działa.
gruenewa
4
Czy mógłbyś wyjaśnić, dlaczego com.sun.net.HttpServer nie jest przenośny w środowisku JRE?
javabeangrinder
3
Nie, nie sądzę. Nie będzie działać na implementacji Java IBMa i może także na innych. I nawet jeśli teraz działa, wewnętrzne interfejsy API mogą ulec zmianie. Dlaczego nie skorzystać z oficjalnego API?
gruenewa
1
Ten link: docs.oracle.com/javase/9/docs/api/java.xml.ws-summary.html mówi, że moduł java.xml.ws jest przestarzały od wersji Java 9.
Erel Segal-Halevi
23

Podoba mi się to pytanie, ponieważ jest to obszar, w którym nieustannie wprowadzane są innowacje i zawsze trzeba mieć lekki serwer, zwłaszcza gdy mówimy o serwerach wbudowanych w małe (er) urządzenia. Myślę, że odpowiedzi dzielą się na dwie szerokie grupy.

  1. Cienki serwer : statyczna zawartość serwera przy minimalnym przetwarzaniu, przetwarzaniu kontekstu lub sesji.
  2. Mały serwer : rzekomo a ma wiele cech serwerowych podobnych do httpD przy minimalnej powierzchni zajmowanej przez użytkownika.

Chociaż mogę uznać biblioteki HTTP, takie jak: Jetty , Apache Http Components , Netty i inne, bardziej przypominające surowe funkcje przetwarzania HTTP. Etykietowanie jest bardzo subiektywne i zależy od rodzaju rzeczy, do których dostarczenia wezwano małe witryny. Rozróżniam to w duchu pytania, szczególnie uwagi o ...

  • „... bez pisania kodu do ręcznej analizy żądań HTTP i ręcznego formatowania odpowiedzi HTTP ...”

Te surowe narzędzia pozwalają ci to zrobić (jak opisano w innych odpowiedziach). Tak naprawdę nie nadają się do gotowego stylu tworzenia lekkiego, wbudowanego lub mini-serwera. Mini-serwer jest czymś, co może dać ci podobną funkcjonalność jak w pełni funkcjonalny serwer internetowy (np. Tomcat ) bez dzwonków i gwizdków, niski poziom głośności, dobra wydajność w 99% przypadków. Cienki serwer wydaje się być bliższy pierwotnemu sformułowaniu, nieco bardziej niż surowy, być może z ograniczoną funkcjonalnością podzbioru, co wystarczy, aby wyglądać dobrze przez 90% czasu. Mój pomysł na raw sprawiłby, że wyglądam dobrze 75% - 89% czasu bez dodatkowego projektowania i kodowania. Myślę, że jeśli / kiedy osiągniesz poziom plików WAR, pozostawiliśmy „małe” dla serwerów bonsi, które wyglądają jak wszystko, co duży serwer robi mniejsze.

Opcje cienkiego serwera

Opcje mini-serwera:

  • Spark Java ... Dobre rzeczy są możliwe dzięki wielu konstrukcjom pomocniczym, takim jak filtry, szablony itp.
  • MadVoc ... chce być bonsai i równie dobrze może być ;-)

Pomiędzy innymi rzeczami do rozważenia, obejmowałbym uwierzytelnianie, sprawdzanie poprawności, internacjonalizację, używanie czegoś takiego jak FreeMaker lub inne narzędzie do szablonów do renderowania danych wyjściowych strony. W przeciwnym razie zarządzanie edycją HTML i parametryzacją może sprawić, że praca z HTTP będzie wyglądać jak krzyżyk noughts-n-crosses. Oczywiście wszystko zależy od tego, jak elastyczna musisz być. Jeśli jest to urządzenie FAKS z menu, może być bardzo proste. Im więcej interakcji, tym „ grubszy ” musi być twój framework. Dobre pytanie, powodzenia!

będzie
źródło
21

Zajrzyj na serwer Jetty Jetty . Znakomity kawałek oprogramowania Open Source, które wydaje się spełniać wszystkie Twoje wymagania.

Jeśli nalegasz, aby rozwinąć własną, spójrz na klasę „httpMessage”.

James Anderson
źródło
Myślę, że api na molo zależy od serwletu.
bezsporne
4
@ Irreputable: Nie, Jetty to wysoce modułowy serwer WWW, który ma kontener serwletów jako jeden z opcjonalnych modułów.
Lawrence Dol
„jest analogiem do funkcjonalności serwera” - tak, to interfejs API „serwletu”. Kontener serwletów wywołuje twoją klasę po przeanalizowaniu nagłówków, plików cookie itp.
James Anderson
1
Dla przypomnienia - Jetty ma własną implementację Servlet API i działa dobrze z Javą SE
James Anderson
4
Pomost jest zbyt duży i ma zbyt dużą krzywą uczenia się, zanim faktyczne wykorzystanie produkcji stanie się możliwe.
ThreaT,
18

Dawno, dawno temu szukałem czegoś podobnego - lekkiego, ale w pełni funkcjonalnego serwera HTTP, który mogłem łatwo osadzić i dostosować. Znalazłem dwa rodzaje potencjalnych rozwiązań:

  • Pełne serwery, które nie są wcale takie lekkie lub proste (dla ekstremalnej definicji lekkości).
  • Naprawdę lekkie serwery, które nie są serwerami HTTP, ale uwielbione przykłady ServerSocket, które nie są nawet zdalnie zgodne z RFC i nie obsługują powszechnie potrzebnej podstawowej funkcjonalności.

Więc ... postanowiłem napisać JLHTTP - Java Lightweight HTTP Server .

Możesz osadzić go w dowolnym projekcie jako pojedynczy (jeśli raczej długi) plik źródłowy lub jako słoik o ~ 50 KB (okrojony o ~ 35 KB) bez żadnych zależności. Stara się być zgodny z RFC i zawiera obszerną dokumentację oraz wiele przydatnych funkcji, jednocześnie zmniejszając wzdęcia do minimum.

Funkcje obejmują: wirtualne hosty, serwery plików z dysku, mapowania typów MIME poprzez standardowy plik mime.types, generowanie indeksu katalogów, pliki powitalne, wsparcie dla wszystkich metod HTTP, warunkowe ETag i obsługa nagłówka If- *, kodowanie przesyłania porcjami, gzip / deflate kompresja, podstawowy HTTPS (dostarczony przez JVM), częściowa zawartość (kontynuacja pobierania), obsługa danych wieloczęściowych / formularzy do przesyłania plików, obsługa wielu kontekstów za pośrednictwem interfejsu API lub adnotacji, analiza parametrów (ciąg zapytania lub x-www-form-urlencoded ciało) itp.

Mam nadzieję, że inni uznają to za przydatne :-)

amichair
źródło
Główna metoda jest dobrym przykładem podstawowego użycia, a FAQ zawiera wiele szczegółów. Jeśli masz sugestie dotyczące ulepszenia istniejących dokumentów, skontaktuj się ze mną bezpośrednio!
amichair
10

Spark jest najprostszy, oto krótki przewodnik: http://sparkjava.com/

Laercio Metzner
źródło
8

Możliwe jest utworzenie serwera http, który zapewnia podstawową obsługę serwletów J2EE za pomocą JDK i apletu apletu w zaledwie kilku wierszach kodu.

Uważam, że jest to bardzo przydatne do serwletów testujących jednostki, ponieważ zaczyna się znacznie szybciej niż inne lekkie pojemniki (używamy pomostów do produkcji).

Większość bardzo lekkich serwerów HTTP nie zapewnia wsparcia dla serwletów, ale potrzebujemy ich, więc pomyślałem, że podzielę się nimi.

Poniższy przykład przedstawia podstawową obsługę serwletów lub wyjątki UnsupportedOperationException dla rzeczy, które nie zostały jeszcze zaimplementowane. Wykorzystuje com.sun.net.httpserver.HttpServer do podstawowej obsługi HTTP.

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
źródło
Brakuje niektórych metod w ServletOutputStream i ServletInputStream
HomeIsWhereThePcIs
nowsza wersja apletu apletu, powyżej pasuje do wersji 3.0 i niższej. Wystarczy dodać brakujące metody w razie potrzeby do przykładu
Carlsen
6

Mogę zdecydowanie polecić przyjrzenie się Simple , szczególnie jeśli nie potrzebujesz możliwości serwletu, ale po prostu masz dostęp do obiektów żądania / odpowiedzi. Jeśli potrzebujesz REST, możesz umieścić na nim Jersey, jeśli chcesz wyprowadzić HTML lub podobny, jest Freemarker. Naprawdę uwielbiam to, co możesz zrobić z tą kombinacją, i jest stosunkowo mało API do nauczenia się.

Waldheinz
źródło
+1. Podoba mi się idea Simple. Pojawiają się jednak problemy przy próbie użycia HTTPS, ponieważ Mamba odbiera funkcję Simple do osadzania.
ThreaT
6

Ten kod jest lepszy niż nasz, wystarczy dodać tylko 2 biblioteki: javax.servelet.jar i org.mortbay.jetty.jar .

Molo klasowe:

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

    }
} 

Klasa serwletu:

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
źródło
2
Pytanie dotyczy wyłącznie Java SE. Przekonasz się, że jetty implementuje API Java EE.
Sridhar
Jetty działa doskonale przy użyciu standardowego Java SE i dlatego spełnia wymagania. To implementuje części API Java EE, to nie trzeba go. Jest różnica.
David Tonhofer,
1
To się nie kwalifikuje. „używając tylko Java SE API” . *.Servlet.jari *.jetty.jaroczywiście nie są częścią Java SE.
icza
czy muszę ustawić molo? czy mogę po prostu usunąć te dwa słoiki i uruchomić ten plik?
Paul Preibisch
4

Wszystkie powyższe odpowiedzi zawierają szczegółowe informacje na temat pojedynczego głównego wątkowego modułu obsługi zapytań.

oprawa:

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

Umożliwia obsługę wielu żądań przez wiele wątków przy użyciu usługi modułu wykonującego.

Więc kod końcowy będzie taki jak poniżej:

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
źródło
3

kasa Prosta . jest to dość prosty serwer, który można osadzić, z wbudowaną obsługą wielu różnych operacji. Szczególnie podoba mi się jego model wątków

Niesamowity!

Olu Smith
źródło
2

Co powiesz na projekt Apache Commons HttpCore ?

Ze strony internetowej: ... HttpCore Goals

  • Implementacja najbardziej podstawowych aspektów transportu HTTP
  • Równowaga między dobrą wydajnością a klarownością i ekspresją API
  • Mały (przewidywalny) ślad pamięci
  • Niezależna biblioteka (brak zewnętrznych zależności poza JRE)
Iqbal
źródło
To prawdopodobnie zbyt niski poziom. Należy przynajmniej dążyć do rozwiązania, które wywołuje kod na poziomie interfejsu API serwletu, chyba że chce się zajmować wszystkimi pojęciami, takimi jak dzielenie, kodowanie itp. Może być fajnie.
David Tonhofer
2

Spróbuj tego https://github.com/devashish234073/Java-Socket-Http-Server/blob/master/README.md

Ten interfejs API tworzy serwer HTTP za pomocą gniazd.

  1. Otrzymuje żądanie z przeglądarki jako tekst
  2. Analizuje je, aby uzyskać informacje o adresie URL, metodzie, atrybutach itp.
  3. Tworzy odpowiedź dynamiczną przy użyciu zdefiniowanego odwzorowania adresu URL
  4. Wysyła odpowiedź do przeglądarki.

Na przykład oto, w jaki sposób konstruktor w Response.javaklasie przekształca surową odpowiedź w odpowiedź 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;
}
Devashish Priyadarshi
źródło
1

Możesz napisać całkiem prosty wbudowany serwer Jetty Java.

Wbudowane Jetty oznacza, że ​​serwer (Jetty) jest dostarczany razem z aplikacją, w przeciwieństwie do wdrażania aplikacji na zewnętrznym serwerze Jetty.

Więc jeśli w podejściu niewbudowanym twoja aplikacja internetowa wbudowana w plik WAR, który został wdrożony na jakimś zewnętrznym serwerze ( Tomcat / Jetty / etc), we wbudowanym Jetty, piszesz aplikację internetową i tworzysz instancję serwera molo w tej samej bazie kodu.

Przykład wbudowanego serwera Jetty Java, który można klonować i użyć: https://github.com/stas-slu/embedded-jetty-java-server-example

Jasio
źródło