servidor HTTP simple en Java usando solo API Java SE

333

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

Para ser claros, el problema que tengo con muchos ejemplos de ServerSocket que he visto en línea es que hacen su propio formato de análisis / respuesta de solicitudes y manejo de errores, que es tedioso, propenso a errores y no es probable que sea completo, y estoy tratando de evitarlo por esas razones.

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

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

preguntador
fuente
3
Umm ... la respuesta corta es no. Si desea algo que maneje la publicación y reciba solicitudes sin escribir manualmente los encabezados http, puede usar servlets. Pero eso es java ee. Si no quieres usar algo así, entonces los sockets y el análisis manual son la única otra opción que conozco.
Matt Phillips
3
Sé que esto no está en el espíritu de SO, pero le insto a que reconsidere su disgusto por las API de Java EE. Como se mencionó en algunas de las respuestas, hay algunas implementaciones muy sencillas, como Jetty, que le permiten incrustar un servidor web en su aplicación independiente sin dejar de aprovechar la API de servlet. Si no puede utilizar la API Java EE por algún motivo, ignore mi comentario :-)
Chris Thompson
1
Los "Servlets" no son realmente "Java EE". Son solo una forma de escribir complementos a los que puede llamar la aplicación circundante en respuesta a la actividad del mensaje (en estos días, generalmente solicitudes HTTP). Proporcionar un entorno de alojamiento de servlets "utilizando solo la API Java SE" es exactamente lo que hacen Jetty y Tomcat. Por supuesto, es posible que desee deshacerse de la complejidad no deseada, pero es posible que deba decidir sobre un subconjunto de los atributos y configuraciones permitidos de GET / POST. Sin embargo, a menudo no vale la pena, excepto por problemas especiales de seguridad / incrustados.
David Tonhofer
1
Puede valer la pena revisar esta lista de servidores http antes de tomar una decisión. java-source.net/open-source/web-servers
ThreaT

Respuestas:

469

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

Aquí hay un ejemplo de inicio copiado de sus documentos (para todas las personas que intentan editarlo, ya que es un código feo, no lo hagas, esta es una copia pegada, no la mía, además nunca deberías editar citas a menos que hayan cambiado) en la fuente original). Puede copiarlo y pegarlo y ejecutarlo 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();
        }
    }

}

Se debe tener en cuenta que la response.length()parte de su ejemplo es mala, debería haberlo sido response.getBytes().length. Incluso entonces, el getBytes()método debe especificar explícitamente el conjunto de caracteres que luego especifique en el encabezado de respuesta. Por desgracia, aunque es un error para los principiantes, después de todo es solo un ejemplo básico de lanzamiento.

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

Esta es la respuesta


En cuanto al uso de com.sun.*clases, tenga en cuenta que esto, al contrario de lo que piensan algunos desarrolladores, no está absolutamente prohibido por las conocidas preguntas frecuentes Por qué los desarrolladores no deben escribir programas que llamen paquetes 'sun' . Las preguntas frecuentes se refieren al sun.*paquete (como sun.misc.BASE64Encoder) para uso interno de Oracle JRE (lo que mataría su aplicación cuando la ejecute en un JRE diferente), no el com.sun.*paquete. Sun / Oracle también acaba de desarrollar software sobre la API Java SE, como todas las demás empresas, como Apache, etc. El uso de com.sun.*clases solo se desaconseja (pero no está prohibido) 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.

BalusC
fuente
19
@Waldheinz; como @Software estás confundiendo sun.*con com.sun.*. Por ejemplo, ¿ves alguna documentación de sun.*API? Mire aquí: java.sun.com/products/jdk/faq/faq-sun-packages.html ¿Cuenta algo sobre esto com.sun.*? El com.sun.*solo se utiliza para su propio software público que no es parte de la API de Java. También desarrollan software sobre la API de Java, como cualquier otra empresa.
BalusC
44
Creo que este es un servidor http muy bueno para usar en casos de prueba de integración. ¡gracias por la pista!
Andreas Petersson
13
Si está utilizando Eclipse y obtiene un error como "Restricción de acceso: el tipo HttpExchange no es accesible debido a la restricción en la biblioteca requerida ...", stackoverflow.com/a/10642163 le indica cómo deshabilitar esa verificación de acceso.
Samuli Pahaoja
13
FWIW esto también está presente en OpenJDK.
Jason C
66
Las clases a las que se hace referencia aquí están etiquetadas @jdk.Exporteden el código fuente de OpenJDK, lo que significa que la API se considera pública y estará disponible en Java 9 (algunos otros com.sun.*paquetes no estarán disponibles debido a Project Jigsaw).
Jules
42

Echa un vistazo a NanoHttpd

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

Se está desarrollando en Github y utiliza Apache Maven para compilaciones y pruebas unitarias "

letronje
fuente
44
Una advertencia: es probable que NanoHTTPD no tenga protección contra los ataques a pie de árbol; debe verificar esto si se publicará en una dirección pública. Con esto me refiero a los ataques donde GET /../../blahblah http/1.1se emite una solicitud como y el servidor camina por encima de la raíz del sitio web y en la tierra de archivos del sistema, sirviendo archivos que pueden utilizarse para comprometer o atacar remotamente el sistema, como un archivo de contraseña.
Lawrence Dol
77
Eso parece estar arreglado. La versión actual genera un 403 if (uri.startsWith ("..") || uri.endsWith ("..") || uri.indexOf ("../")> = 0).
Lena Schimmel
55
No entiendo cómo esta es una respuesta a esta pregunta.
kimathie
28

La solución com.sun.net.httpserver no es portátil en todos los 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("<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)

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<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
fuente
1
+1 por ser portátil. Lástima que no pueda establecer el tipo de contenido de respuesta tal como está text/xml.
icza
1
Creo que podría hacer <code> class Server implementa Provider <DataSource> {</code> ... y luego especificar el Content-Type dentro del método <code> getContentType () </code> del DataSource. Además, también puede inyectar el WebServiceContext: <code> @Resource WebServiceContext ctx; </code> para establecer otros encabezados y leer los parámetros de solicitud. Desafortunadamente, configurar el tipo de contenido a través de WebServiceContext no funciona.
gruenewa
44
¿Podría explicar por qué com.sun.net.HttpServer no es portátil en JRE, por favor?
javabeangrinder
3
No, no lo creo. No funcionará en la implementación Java de IBM y quizás también en otros. E incluso si funciona ahora, las API internas pueden cambiar. ¿Por qué no solo usar la API oficial?
gruenewa
1
Este enlace: docs.oracle.com/javase/9/docs/api/java.xml.ws-summary.html dice que el módulo java.xml.ws está en desuso desde Java 9.
Erel Segal-Halevi
23

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

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

Si bien podría considerar que las bibliotecas HTTP como: Jetty , Apache Http Components , Netty y otras se parecen más a las instalaciones de procesamiento HTTP sin procesar. El etiquetado es muy subjetivo y depende de los tipos de cosas que ha sido llamado a entregar para sitios pequeños. Hago esta distinción en el espíritu de la pregunta, particularmente el comentario sobre ...

  • "... sin escribir código para analizar manualmente las solicitudes HTTP y formatear manualmente las respuestas HTTP ..."

Estas herramientas en bruto le permiten hacer eso (como se describe en otras respuestas). Realmente no se prestan a un estilo listo para usar de hacer un servidor ligero, incrustado o mini-servidor. Un mini servidor es algo que puede brindarle una funcionalidad similar a un servidor web con todas las funciones (como, por ejemplo, Tomcat ) sin campanas y silbatos, bajo volumen, buen rendimiento el 99% del tiempo. Un servidor delgado parece estar más cerca de la redacción original solo un poco más que en bruto, tal vez con una funcionalidad de subconjunto limitada, suficiente para que te veas bien el 90% del tiempo. Mi idea de raw sería hacerme quedar bien del 75% al ​​89% del tiempo sin diseño y codificación adicionales. Creo que si / cuando alcanzas el nivel de archivos WAR, dejamos el "pequeño" para servidores bonsi que parece todo lo que un servidor grande hace más pequeño.

Opciones de servidor delgado

Opciones de miniservidor:

  • Spark Java ... Las cosas buenas son posibles con muchas construcciones auxiliares como filtros, plantillas, etc.
  • MadVoc ... apunta a ser bonsai y bien podría ser tal ;-)

Entre las otras cosas a considerar, incluiría autenticación, validación, internacionalización, usando algo como FreeMaker u otra herramienta de plantilla para representar la salida de la página. De lo contrario, es probable que administrar la edición y la parametrización HTML haga que trabajar con HTTP parezca noughts-n-Cross Naturalmente, todo depende de cuán flexible necesite ser. Si se trata de una máquina de fax controlada por menús, puede ser muy simple. Cuantas más interacciones, más ' grueso ' debe ser tu marco. Buena pregunta, buena suerte!

será
fuente
21

Echa un vistazo al servidor web "Jetty" Jetty . Excelente pieza de software de código abierto que parece cumplir con todos sus requisitos.

Si insiste en lanzar el suyo propio, eche un vistazo a la clase "httpMessage".

James Anderson
fuente
Creo que el embarcadero api depende del servlet.
irreputable
44
@Irreputable: No, Jetty es un servidor web altamente modular, que tiene un contenedor de servlets como uno de sus módulos opcionales.
Lawrence Dol
"es un análogo para la funcionalidad del servidor" - sí, es la API "servlet". El contenedor de servlets llama a su clase después de analizar los encabezados, las cookies, etc.
James Anderson
1
Solo para el registro: Jetty viene con su propia implementación de la API de Servlet y funciona bien con Java SE
James Anderson el
44
Jetty es demasiado grande y tiene demasiada curva de aprendizaje antes de que el uso de producción real se convierta en una posibilidad.
ThreaT
18

É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 posibles soluciones:

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

Entonces ... me propuse escribir JLHTTP - El servidor HTTP ligero de Java .

Puede incrustarlo en cualquier proyecto como un único archivo fuente (si es bastante largo), o como un jar de ~ 50K (~ 35K despojado) sin dependencias. Se esfuerza por cumplir con RFC e incluye una amplia documentación y muchas características útiles, manteniendo la hinchazón al mínimo.

Las características incluyen: hosts virtuales, servicio de archivos desde el disco, asignaciones de 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 de encabezado If- *, codificación de transferencia fragmentada, gzip / deflate compresión, HTTPS básico (como lo proporciona la JVM), contenido parcial (continuación de descarga), manejo de datos multiparte / formulario para cargas de archivos, manejadores de contexto múltiples a través de API o anotaciones, análisis de parámetros (cadena de consulta o x-www-form-urlencoded cuerpo), etc.

Espero que otros lo encuentren útil :-)

amichair
fuente
El método principal es un buen ejemplo de uso básico, y las preguntas frecuentes incluyen muchos de los detalles. Si tiene sugerencias para mejorar los documentos existentes, ¡no dude en ponerse en contacto conmigo directamente!
amichair
8

Es posible crear un httpserver que brinde soporte básico para servlets J2EE con solo el JDK y la API de servlet en solo unas pocas líneas de código.

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

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

El siguiente ejemplo proporciona soporte básico de servlet, o throws y UnsupportedOperationException para cosas que aún no están implementadas. Utiliza com.sun.net.httpserver.HttpServer para soporte básico de 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
fuente
Faltan algunos métodos en ServletOutputStream y ServletInputStream
HomeIsWhereThePcIs
versión más nueva de la API de servlet, la anterior se ajusta a la 3.0 y la inferior. Solo agregue los métodos faltantes según sea necesario en el ejemplo
f.carlsen
6

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

Waldheinz
fuente
+1. Me gustan las ideas detrás de Simple. Sin embargo, surgen problemas al intentar usar HTTPS porque Mamba elimina la función "integrable" de Simple.
ThreaT
6

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

Embarcadero de clase:

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();
    }
}
leandro
fuente
2
La pregunta pide una solución puramente Java SE. Encontrará que el embarcadero implementa la API Java EE.
Sridhar
Jetty funciona perfectamente bien con Java SE estándar y, por lo tanto, cumple con los requisitos. Se implementa partes de la API de Java EE, no necesitan la misma. Hay una diferencia.
David Tonhofer
1
Esto no califica. "utilizando solo la API Java SE" . *.Servlet.jary *.jetty.jarobviamente no son parte de Java SE.
icza
¿Necesito configurar el embarcadero? o ¿puedo simplemente desconectar esos dos frascos y ejecutar este archivo?
Paul Preibisch
4

Todo lo anterior responde a detalles sobre el controlador de solicitud de subproceso principal único.

ajuste:

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

Permite el servicio de múltiples solicitudes a través de múltiples hilos utilizando el servicio ejecutor.

Entonces el código final será algo como a continuación:

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
fuente
3

Pago simple . es un servidor incrustable bastante simple con soporte integrado para una gran variedad de operaciones. Particularmente me encanta su modelo de roscado.

¡Asombroso!

Olu Smith
fuente
2

¿Qué hay del proyecto Apache Commons HttpCore ?

Desde el sitio web: ... Objetivos HttpCore

  • Implementación de los aspectos de transporte HTTP más fundamentales.
  • Equilibrio entre el buen rendimiento y la claridad y expresividad de API
  • Huella de memoria pequeña (predecible)
  • Biblioteca autónoma (sin dependencias externas más allá de JRE)
Iqbal
fuente
Eso es probablemente de muy bajo nivel. Al menos, uno debe apuntar a una solución que llame a su código en el nivel de API de servlet, a menos que quiera tratar todos los conceptos como fragmentación, codificación, etc. Sin embargo, puede ser divertido.
David Tonhofer
2

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

Esta API ha creado un servidor HTTP utilizando sockets.

  1. Recibe una solicitud del navegador como texto
  2. Lo analiza para recuperar información de URL, método, atributos, etc.
  3. Crea una respuesta dinámica utilizando la asignación de URL definida
  4. Envía la respuesta al navegador.

Por ejemplo, así es como el constructor de la Response.javaclase convierte una respuesta sin formato en una respuesta 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
fuente
1

Puede escribir un servidor Jetty Java incrustado bastante simple .

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

Entonces, si en un enfoque no integrado, su aplicación web incorporada en el archivo WAR que se implementó en un servidor externo ( Tomcat / Jetty / etc.), en Jetty integrado, usted escribe la aplicación web y crea una instancia del servidor de muelle en la misma base de código.

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

Johnny
fuente