servidor HTTP simple en Java utilizando solo la API SE de Java

¿Hay alguna manera de crear un servidor HTTP muy básico (que solo admita GET / POST) en Java utilizando solo la API Java SE, sin escribir código para analizar manualmente las solicitudes HTTP y formatear las respuestas HTTP manualmente? La API Java SE encapsula muy bien la funcionalidad del cliente HTTP en HttpURLConnection, pero ¿existe un análogo para la funcionalidad del servidor HTTP?

Para que quede claro, el problema que tengo con muchos ejemplos de ServerSocket que he visto en línea es que hacen su propio formato de solicitud de análisis / respuesta y manejo de errores, que es tedioso, propenso a errores y no es exhaustivo, y estoy tratando de evitarlo por esos motivos.

Como un ejemplo de la manipulación manual de HTTP que estoy tratando de evitar:

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

Desde Java SE 6, hay un servidor HTTP incorporado en Sun Oracle JRE. El resumen del paquete com.sun.net.httpserver describe las clases involucradas y contiene ejemplos.

Aquí hay un ejemplo de patada de salida eliminado de sus documentos, puede simplemente copiarlo y pegarlo en 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(); } } } 

Notado debe ser que la parte response.length() en su ejemplo es mala, debería haber sido response.getBytes().length . Incluso entonces, el método getBytes() debe especificar explícitamente el getBytes() caracteres que luego especifique en el encabezado de respuesta. Desgraciadamente, aunque sea un error para los principiantes, después de todo es solo un ejemplo básico de patada de salida.

Ejecútelo y vaya a http: // localhost: 8000 / test y verá la siguiente respuesta:

Esta es la respuesta


En cuanto al uso de las clases com.sun.* , Tenga en cuenta que esto es, al contrario de lo que piensan algunos desarrolladores, absolutamente no prohibido por las conocidas preguntas frecuentes ¿Por qué los desarrolladores no deben escribir progtwigs que llaman paquetes ‘sol’ ? Las preguntas frecuentes se refieren al paquete sun.* (Como sun.misc.BASE64Encoder ) para el uso interno de Oracle JRE (lo que mataría a su aplicación cuando lo ejecuta en un JRE diferente), no al paquete com.sun.* . Sun / Oracle también solo desarrollan software sobre la API de Java SE, como cualquier otra compañía como Apache, etc. El uso de clases com.sun.* Solo se desaconseja (pero no se prohíbe) cuando se trata de una implementación de una determinada API de Java, como GlassFish (Java EE impl), Mojarra (JSF impl), Jersey (JAX-RS impl), etc. .

Echa un vistazo a NanoHttpd

“NanoHTTPD es un servidor HTTP liviano diseñado para integrarse en otras aplicaciones, publicado bajo una licencia BSD modificada.

Se está desarrollando en Github y utiliza Apache Maven para comstackciones y pruebas unitarias “.

La solución com.sun.net.httpserver no es portátil en JRE. Es mejor usar la API oficial de servicios web en javax.xml.ws para arrancar un servidor HTTP mínimo …

 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)

EDITAR: ¡esto realmente funciona! El código anterior se parece a Groovy o algo así. Aquí hay una traducción a Java que probé:

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

Eche un vistazo al Jetty del servidor web “Jetty”. Excelente pieza de software de código abierto que parece cumplir con todos sus requisitos.

Si insiste en rodar el suyo, eche un vistazo a la clase “httpMessage”.

Me gusta esta pregunta porque esta es un área donde hay una innovación continua y siempre hay una necesidad de tener un servidor liviano, especialmente cuando se habla de servidores integrados en dispositivos pequeños (er). Creo que las respuestas se dividen en dos grandes grupos.

  1. Thin-server : contenido estático de servidor con procesamiento mínimo, contexto o procesamiento de sesión.
  2. Servidor pequeño : ostensiblemente, tiene muchas cualidades de servidor tipo httpD con una huella tan pequeña como usted puede salirse con la suya.

Aunque podría considerar que las bibliotecas HTTP como: Jetty , Apache Http Components , Netty y otras son más como instalaciones de procesamiento HTTP sin procesar. El etiquetado es muy subjetivo y depende del tipo de cosas que haya solicitado para sitios pequeños. Hago esta distinción en el espíritu de la pregunta, particularmente la observación sobre …

  • “… sin escribir código para analizar manualmente las solicitudes HTTP y formatear las respuestas HTTP manualmente …”

Estas herramientas crudas te permiten hacer eso (como se describe en otras respuestas). En realidad, no se prestan a un estilo listo para usar: hacer un servidor ligero, integrado o mini servidor. Un mini servidor es algo que puede darle una funcionalidad similar a la de un servidor web con todas las funciones (como por ejemplo, Tomcat ) sin campanas y silbatos, bajo volumen, buen rendimiento el 99% del tiempo. Un thin server parece más cercano al fraseo original que un poco más que crudo, quizás con una funcionalidad subconjunto limitada, suficiente para que te veas bien el 90% del tiempo. Mi idea de Raw me hace lucir bien el 75% – 89% del tiempo sin diseño y encoding adicionales. Creo que si alcanzas el nivel de los archivos WAR, dejamos el “pequeño” para los servidores bonsi que se parece a todo lo que un servidor grande hace más pequeño.

Opciones de servidor delgado

  • Oso pardo
  • UniRest (múltiples idiomas)
  • NanoHTTPD (solo un archivo)

Opciones de mini servidor:

  • Spark Java … Las cosas buenas son posibles con muchas construcciones de ayuda como filtros, plantillas, etc.
  • MadVoc … pretende ser bonsai y podría ser así 😉

Entre otras cosas a considerar, incluiría la autenticación, la validación, la internacionalización, el uso de algo como FreeMaker u otra herramienta de plantilla para generar resultados de página. De lo contrario, la gestión de la edición HTML y la parametrización probablemente hagan que trabajar con HTTP parezca noughts-n-crosses. Naturalmente, todo depende de la flexibilidad que necesita ser. Si se trata de una máquina de FAX controlada por menús, puede ser muy simple. Cuantas más interacciones, másgrueso ” debe ser su marco. Buena pregunta, ¡buena suerte!

Érase una vez que estaba buscando algo similar, un servidor HTTP liviano pero totalmente funcional que pudiera incrustar y personalizar fácilmente. Encontré dos tipos de soluciones potenciales:

  • Servidores completos que no son tan livianos o simples (para una definición extrema de peso liviano).
  • Servidores verdaderamente livianos que no son exactamente servidores HTTP, pero glorificaron los ejemplos de ServerSocket que ni siquiera son remotamente compatibles con RFC y no son compatibles con la funcionalidad básica comúnmente requerida.

Entonces … me puse a escribir JLHTTP – El servidor HTTP Lightweight de Java .

Puede incrustarlo en cualquier proyecto como un único archivo fuente (si es bastante largo), o como un jar ~ 50K (~ 35K stripped) sin dependencias. Se esfuerza por ser compatible con RFC e incluye una amplia documentación y muchas funciones útiles a la vez que minimiza la hinchazón.

Las características incluyen: hosts virtuales, servicio de disco, mapeos tipo mime a través del archivo mime.types estándar, generación de índice de directorio, archivos de bienvenida, soporte para todos los métodos HTTP, ETags condicionales y soporte If- * header, encoding de transferencia fragmentada, gzip / deflate compresión, HTTPS básico (según lo provisto por JVM), contenido parcial (continuación de descarga), manejo multipart / form-data para cargas de archivos, múltiples manejadores de contexto a través de API o anotaciones, análisis de parámetros (query string o x-www-form-urlencoded cuerpo), etc.

Espero que otros lo encuentren útil 🙂

Un servidor web muy básico escrito en java se puede encontrar aquí http://library.sourcerabbit.com/v/?id=19

Spark es el más simple, aquí hay una guía de inicio rápido: http://sparkjava.com/

Es posible crear un servidor https que proporcione soporte básico para los servlets J2EE con solo el JDK y la astackción de servlet en unas pocas líneas de código.

He encontrado que esto es muy útil para los servlets de prueba unitaria, ya que comienza mucho más rápido que otros contenedores livianos (utilizamos embarcadero para la producción).

La mayoría de los httpservers muy livianos no brindan soporte para los servlets, pero los necesitamos, así que pensé en compartirlos.

El siguiente ejemplo proporciona soporte de servlet básico o throws y UnsupportedOperationException para cosas que aún no se han implementado. Utiliza el servidor com.sun.net.httpserver.HttpServer para el soporte HTTP básico.

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

Recomiendo encarecidamente buscar en Simple , especialmente si no necesita capacidades de Servlets, sino simplemente acceder a los objetos solicitud / respuesta. Si necesita REST, puede poner a Jersey encima, si necesita sacar HTML o similar hay Freemarker. Realmente me encanta lo que puedes hacer con esta combinación, y hay relativamente poca API para aprender.

También puede echar un vistazo a algunos marcos de aplicación de NIO, como:

  1. Netty: http://jboss.org/netty
  2. Apache Mina: http://mina.apache.org/ o su subproyecto AsyncWeb: http://mina.apache.org/asyncweb/

Este código es mejor que el nuestro, solo necesita agregar 2 libs: javax.servelet.jar y org.mortbay.jetty.jar .

Clase Jetty:

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

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

pago simple . es un servidor empotrable bastante simple con soporte integrado para una gran variedad de operaciones. Me encanta su modelo de roscado.

¡Asombroso!

Echa un vistazo. Mira https://github.com/yegor256/takes para obtener información rápida

¿Qué tal el proyecto Apache Commons HttpCore ?

Desde el sitio web: … HttpCore Goals

  • Implementación de los aspectos de transporte HTTP más fundamentales
  • Equilibrio entre un buen rendimiento y la claridad y expresividad de la API
  • Huella de memoria pequeña (predecible)
  • Biblioteca autónoma (sin dependencias externas más allá de JRE)

Puede escribir un servidor Jetty Java embebido bastante simple.

Embedded Jetty significa que el servidor (Jetty) se envía junto con la aplicación en lugar de implementar la aplicación en el servidor Jetty externo.

Entonces, si en un enfoque no integrado tu aplicación web está integrada en el archivo WAR que se implementó en algún servidor externo ( Tomcat / Jetty / etc), en un Jetty integrado, escribes la aplicación web y crea una instancia del servidor jetty en la misma base de código.

Un ejemplo para el servidor Jetty Java incrustado que puedes clonar y usar: https://github.com/stas-slu/embedded-jetty-java-server-example

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

Esta aplicación ha creado un servidor http utilizando sockets. Detalles:
1. Recibe la solicitud del navegador como texto
2. Lo busca para recuperar información de url, método, atributos, etc.
3. Crea una respuesta dinámica usando el mapeo url definido
4. Envía la respuesta al navegador.

Por ejemplo, así es como el constructor en la clase “Response.java” convierte una respuesta bruta en una respuesta http:

Respuesta pública (String resp) {
Fecha de fecha = nueva Fecha ();
String start = “HTTP / 1.1 200 OK \ r \ n”;
String header = “Fecha:” + 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;
}