semplice server HTTP in Java utilizzando solo l’API Java SE

C’è un modo per creare un server HTTP molto semplice (che supporta solo GET / POST) in Java usando solo l’API Java SE, senza scrivere codice per analizzare manualmente le richieste HTTP e formattare manualmente le risposte HTTP? L’API Java SE racchiude in modo elegante la funzionalità del client HTTP in HttpURLConnection, ma esiste un analogo per la funzionalità del server HTTP?

Per essere chiari, il problema che ho riscontrato con molti esempi ServerSocket che ho visto online è che essi eseguono le proprie richieste di parsing / response formattazione e gestione degli errori, che è noioso, sobject a errori e che probabilmente non è completo, e sto cercando di evitarlo per queste ragioni.

Come esempio della manipolazione HTTP manuale che sto cercando di evitare:

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

    Da Java SE 6, c’è un server HTTP integrato in Sun Oracle JRE. Il sumrio del pacchetto com.sun.net.httpserver delinea le classi coinvolte e contiene esempi.

    Ecco un esempio di kickoff copypasted dai loro documenti, puoi semplicemente copiare e non far funzionare su 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(); } } } 

    Notato dovrebbe essere che la parte response.length() nel loro esempio è ctriggers, avrebbe dovuto essere response.getBytes().length . Anche in questo caso, il metodo getBytes() deve specificare esplicitamente il set di caratteri che viene specificato nell’intestazione della risposta. Ahimè, sebbene sia fuorviante per i principianti, dopotutto è solo un esempio base di kickoff.

    Eseguilo e vai a http: // localhost: 8000 / test e vedrai la seguente risposta:

    Questa è la risposta


    Per quanto riguarda l’uso com.sun.* classi com.sun.* , Si noti che questo è, contrariamente a quanto pensano alcuni sviluppatori, assolutamente non vietato dalle ben note FAQ Perché gli sviluppatori non devono scrivere programmi che chiamano pacchetti ‘sole’ . Quelle FAQ riguardano il pacchetto sun.* (Come sun.misc.BASE64Encoder ) per l’uso interno da parte di Oracle JRE (che quindi ucciderebbe l’applicazione quando la si esegue su un JRE diverso), non il pacchetto com.sun.* . Sun / Oracle sviluppa anche software in aggiunta alle API Java SE come ad esempio ogni altra azienda come Apache e così via. L’uso com.sun.* classi com.sun.* È solo scoraggiato (ma non vietato) quando riguarda un’implementazione di una determinata API Java, come GlassFish (Java EE impl), Mojarra (JSF impl), Jersey (JAX-RS impl), ecc. .

    Dai un’occhiata a NanoHttpd

    “NanoHTTPD è un server HTTP leggero progettato per l’incorporamento in altre applicazioni, rilasciato con una licenza BSD modificata.

    È in fase di sviluppo presso Github e utilizza Apache Maven per build e test di unità ”

    La soluzione com.sun.net.httpserver non è portabile tra i JRE. È meglio utilizzare l’API webservices ufficiale in javax.xml.ws per avviare un server HTTP minimo …

     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("

    Hello There!

    ")); } 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: funziona davvero! Il codice sopra sembra Groovy o qualcosa del genere. Ecco una traduzione in Java che ho testato:

     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 { public Source invoke(Source request) { return new StreamSource(new StringReader("

    Hello There!

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

    Dai un’occhiata al molo del server web “Jetty”. Superba parte del software Open Source che sembra soddisfare tutti i tuoi requisiti.

    Se insisti a far girare il tuo, dai un’occhiata alla class “httpMessage”.

    Mi piace questa domanda perché questa è un’area in cui c’è innovazione continua e c’è sempre bisogno di avere un server leggero soprattutto quando si parla di server embedded in piccoli dispositivi. Penso che le risposte rientrino in due ampi gruppi.

    1. Thin-server : contenuto statico server-up con elaborazione minima, contesto o sessione.
    2. Piccolo server : apparentemente ha molte qualità di server simili a httpD con un ingombro ridotto che puoi farla franca.

    Mentre potrei considerare librerie HTTP come: Jetty , Apache Http Components , Netty e altri per essere più simili a strutture di elaborazione HTTP non elaborate. L’etichettatura è molto soggettiva e dipende dal tipo di cose che sei stato chiamato a fornire per i siti di piccole dimensioni. Faccio questa distinzione nello spirito della domanda, in particolare l’osservazione su …

    • “… senza scrivere codice per analizzare manualmente le richieste HTTP e formattare manualmente le risposte HTTP …”

    Questi strumenti grezzi ti permettono di farlo (come descritto in altre risposte). In realtà non si prestano a uno stile pronto per creare un server leggero, embedded o mini-server. Un mini-server è qualcosa che può darti funzionalità simili a un server web con funzioni complete (come ad esempio Tomcat ) senza campane e fischi, volume basso, buone prestazioni il 99% delle volte. Un thin-server sembra più vicino al fraseggio originale solo un po ‘più grezzo, forse con una funzionalità di sottoinsieme limitata, abbastanza per farti sembrare buono il 90% delle volte. La mia idea di raw mi farebbe apparire al 75% – 89% delle volte senza design e codifica extra. Penso che se / quando raggiungi il livello dei file WAR, abbiamo lasciato il “piccolo” per i server bonsi che assomiglia a tutto ciò che un server grande fa più piccolo.

    Opzioni thin-server

    • Grizzly
    • UniRest (più lingue)
    • NanoHTTPD (solo un file)

    Opzioni del mini-server:

    • Spark Java … Le cose buone sono possibili con molti costrutti helper come filtri, modelli, ecc.
    • MadVoc … si propone di essere bonsai e potrebbe essere tale 😉

    Tra le altre cose da considerare, includerei l’autenticazione, la convalida, l’internazionalizzazione, l’uso di qualcosa come FreeMaker o altri strumenti modello per il rendering dell’output della pagina. In caso contrario, la gestione della modifica e della parametrizzazione HTML probabilmente renderà il lavoro con HTTP simile a noughts-n-crosses. Naturalmente tutto dipende da quanto flessibile è necessario essere. Se si tratta di una macchina FAX basata su menu, può essere molto semplice. Maggiore è il numero di interazioni, piùspessa ” deve essere la tua struttura. Buona domanda, buona fortuna!

    C’era una volta che cercavo qualcosa di simile: un server HTTP leggero ma completamente funzionale che avrei potuto facilmente integrare e personalizzare. Ho trovato due tipi di soluzioni potenziali:

    • Server completi che non sono così leggeri o semplici (per un’estrema definizione di leggerezza).
    • Server veramente leggeri che non sono server HTTP, ma esempi ServerSocket glorificati che non sono nemmeno remotamente conformi agli standard RFC e non supportano le funzionalità di base comunemente necessarie.

    Quindi … ho deciso di scrivere JLHTTP – Il Java Lightweight HTTP Server .

    Puoi incorporarlo in qualsiasi progetto come un singolo file sorgente (anche se piuttosto lungo) o come un jar da ~ 50K (~ 35K spogliato) senza dipendenze. Si sforza di essere conforms a RFC e include un’ampia documentazione e molte funzioni utili, mantenendo al minimo il bloat.

    Le caratteristiche includono: host virtuali, file serving da disco, mapping di tipo mime tramite file standard mime.types, generazione dell’indice di directory, file di benvenuto, supporto per tutti i metodi HTTP, supporto ETags condizionale e supporto If- *, codifica di trasferimento chunked, gzip / deflate compressione, HTTPS di base (come fornito dalla JVM), contenuto parziale (download continuation), gestione multipart / form-data per upload di file, gestori di contesto multipli tramite API o annotazioni, parsing di parametri (stringa di query o x-www-form-urlencoded corpo), ecc.

    Spero che gli altri lo trovino utile 🙂

    Un server Web di base scritto in java può essere trovato qui http://library.sourcerabbit.com/v/?id=19

    Spark è il più semplice, ecco una guida rapida: http://sparkjava.com/

    È ansible creare un httpserver che fornisce il supporto di base per i servlet J2EE con solo JDK e l’API servlet in poche righe di codice.

    Ho trovato questo molto utile per servlet test di unità, in quanto inizia molto più veloce di altri contenitori leggeri (usiamo il molo per la produzione).

    Gli httpserver più leggeri non forniscono supporto per i servlet, ma ne abbiamo bisogno, quindi ho pensato di condividerlo.

    L’esempio seguente fornisce supporto di base per servlet, o throw e UnsupportedOperationException per roba non ancora implementata. Utilizza com.sun.net.httpserver.HttpServer per il supporto http di base.

     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 postData; private final ServletInputStream is; private final Map attributes = new HashMap<>(); private RequestWrapper(HttpServletRequest request, HttpExchange ex, Map 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 getHeaders(String name) { return new Vector(ex.getRequestHeaders().get(name)).elements(); } @Override public Enumeration getHeaderNames() { return new Vector(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 getAttributeNames() { return new Vector(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 getParameterMap() { return postData; } @Override public Enumeration getParameterNames() { return new Vector(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 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 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 createUnimplementAdapter(Class 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()); } } 

    Consiglio vivamente di cercare in Simple , soprattutto se non hai bisogno delle funzionalità Servlet ma semplicemente di accedere agli oggetti richiesta / risposta. Se hai bisogno di REST puoi metterlo sopra, se hai bisogno di generare HTML o simili c’è Freemarker. Mi piace molto quello che puoi fare con questa combinazione e ci sono relativamente poche API da imparare.

    Si può anche dare un’occhiata ad alcuni framework di applicazioni NIO come:

    1. Netty: http://jboss.org/netty
    2. Apache Mina: http://mina.apache.org/ o il suo sottoprogetto AsyncWeb: http://mina.apache.org/asyncweb/

    Questo codice è migliore del nostro, è sufficiente aggiungere 2 librerie: javax.servelet.jar e org.mortbay.jetty.jar .

    Molo di class:

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

    Classe servlet:

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

    checkout Semplice . è un server semplice e incoraggiante con supporto integrato per una varietà di operazioni. Adoro particolarmente il suo modello di threading ..

    Stupefacente!

    Il check-out takes . Guarda https://github.com/yegor256/takes per informazioni rapide

    Che ne dici del progetto Apache Commons HttpCore ?

    Dal sito web: … HttpCore Goals

    • Implementazione degli aspetti di trasporto HTTP più fondamentali
    • Equilibrio tra buone prestazioni e chiarezza ed espressività dell’API
    • Memoria di memoria piccola (prevedibile)
    • Libreria autonoma (nessuna dipendenza esterna oltre JRE)

    Puoi scrivere un server Jetty Java embedded piuttosto semplice.

    Embedded Jetty significa che il server (Jetty) è stato spedito insieme all’applicazione anziché distribuire l’applicazione sul server Jetty esterno.

    Quindi, se in un approccio non incorporato la tua webapp è incorporata nel file WAR che è stato distribuito su un server esterno ( Tomcat / Jetty / etc), nel Jetty incorporato, scrivi la webapp e istanzia il server jetty nella stessa base di codice.

    Un esempio per il server Jetty Java integrato è ansible creare cloni e utilizzare: https://github.com/stas-slu/embedded-jetty-java-server-example

    Prova questo https://github.com/devashish234073/Java-Socket-Http-Server/blob/master/README.md

    Questa API ha creato un server http che utilizza socket. Dettagli:
    1. Richiede la richiesta dal browser come testo
    2.Seleziona per recuperare informazioni, metodo, attributi, ecc.
    3. Crea una risposta dynamic usando la mapping URL definita
    4. Invia la risposta al browser.

    Ad esempio, ecco come il costruttore nella class “Response.java” converte una risposta non elaborata in una risposta http:

    risposta pubblica (stringa resp) {
    Data data = nuova Data ();
    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”;
    intestazione + = “\ r \ n”;
    this.resp = inizio + intestazione + risp;
    }