servidor HTTP simples em Java usando apenas Java SE API

Existe uma maneira de criar um servidor HTTP muito básico (suportando apenas GET / POST) em Java usando apenas a API Java SE, sem escrever código para analisar manualmente as solicitações HTTP e formatar manualmente as respostas HTTP? A API Java SE encapsula muito bem a funcionalidade do cliente HTTP em HttpURLConnection, mas existe um analógico para a funcionalidade do servidor HTTP?

Só para esclarecer, o problema que tenho com muitos exemplos de ServerSocket que eu vi online é que eles fazem seus próprios pedidos de formatação de análise / resposta e tratamento de erros, o que é entediante, propenso a erros e provavelmente não é abrangente, e estou tentando evitá-lo por essas razões.

Como um exemplo da manipulação HTTP manual que estou tentando evitar:

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

Desde o Java SE 6, há um servidor HTTP embutido no Sun Oracle JRE. O resumo do pacote com.sun.net.httpserver descreve as classs envolvidas e contém exemplos.

Aqui está um exemplo de kickoff copiado de seus documentos, você pode simplesmente copiar e colar o 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(); } } } 

Deve ser notado que a parte response.length() em seu exemplo é ruim, deveria ter sido response.getBytes().length . Mesmo assim, o método getBytes() deve especificar explicitamente o conjunto de caracteres que você especifica no header de resposta. Infelizmente, apesar de ter sido enganador para iniciantes, afinal de contas é apenas um exemplo básico de kickoff.

Execute-o e vá para http: // localhost: 8000 / test e você verá a seguinte resposta:

Esta é a resposta


Quanto ao uso de classs com.sun.* , Note que isto é, ao contrário do que alguns desenvolvedores pensam, absolutamente não é proibido pelo bem conhecido FAQ Por que os desenvolvedores não devem gravar programas que chamam pacotes de ‘sol’ . Essa FAQ se refere ao pacote sun.* (Como sun.misc.BASE64Encoder ) para uso interno pelo Oracle JRE (que mataria seu aplicativo quando você o executa em um JRE diferente), não o pacote com.sun.* . A Sun / Oracle também apenas desenvolve software sobre a API Java SE, como qualquer outra empresa, como o Apache e assim por diante. O uso de classs com.sun.* É apenas desencorajado (mas não proibido) quando se trata de uma implementação de uma determinada API Java, como GlassFish (Java EE impl), Mojarra (JSF impl), Jersey (JAX-RS), etc .

Confira NanoHttpd

“O NanoHTTPD é um servidor HTTP leve projetado para incorporação em outros aplicativos, liberado sob uma licença BSD Modificada.

Ele está sendo desenvolvido no Github e usa o Apache Maven para compilações e testes unitários ”

A solução com.sun.net.httpserver não é portátil nos JREs. É melhor usar a API oficial de webservices em javax.xml.ws para inicializar um 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)

EDIT: isso realmente funciona! O código acima se parece com o Groovy ou algo assim. Aqui está uma tradução para Java que testei:

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

Dê uma olhada no Jetty do servidor Web “Jetty”. Excelente peça de software de código aberto que parece satisfazer todos os seus requisitos.

Se você insistir em rolar o seu próprio então dê uma olhada na class “httpMessage”.

Eu gosto desta questão porque esta é uma área onde há inovação contínua e sempre há uma necessidade de ter um servidor leve, especialmente quando se fala de servidores embutidos em dispositivos pequenos. Eu acho que as respostas caem em dois grandes grupos.

  1. Thin-server : conteúdo estático de servidor com processamento, contexto ou session de processamento mínimos.
  2. Pequeno servidor : ostensivamente tem muitas qualidades de servidores semelhantes a httpD com uma pegada tão pequena quanto possível.

Embora eu possa considerar bibliotecas HTTP como: Jetty , Apache Http Components , Netty e outros, para ser mais como um recurso de processamento HTTP bruto. A rotulagem é muito subjetiva e depende do tipo de coisa que você pediu para entregar em pequenos sites. Eu faço essa distinção no espírito da questão, particularmente a observação sobre …

  • “… sem escrever código para analisar manualmente as solicitações HTTP e formatar manualmente as respostas HTTP …”

Essas ferramentas cruas permitem que você faça isso (conforme descrito em outras respostas). Eles realmente não se prestam a um estilo de preparação de luz, incorporado ou mini-servidor. Um mini-servidor é algo que pode dar a você uma funcionalidade semelhante a um servidor da Web de function completa (como o Tomcat ), sem sinos e assobios, baixo volume e bom desempenho 99% do tempo. Um servidor thin parece mais próximo do fraseado original apenas um pouco mais do que simples, talvez com uma funcionalidade de subconjunto limitada, o suficiente para fazer você parecer bem 90% do tempo. Minha ideia de matéria-prima me faz parecer bem 75% – 89% do tempo sem design e codificação extras. Eu acho que se você chegar ao nível dos arquivos WAR, nós deixamos o “pequeno” para servidores bons que se parece com tudo que um servidor grande faz.

Opções de servidor thin

  • Grisalho
  • UniRest (idiomas múltiplos)
  • NanoHTTPD (apenas um arquivo)

Opções de mini-servidor:

  • Spark Java … Boas coisas são possíveis com muitas construções auxiliares como Filtros, Modelos, etc.
  • MadVoc … pretende ser bonsai e poderia ser assim 😉

Entre outras coisas a considerar, eu includeia autenticação, validação, internacionalização, usando algo como o FreeMaker ou outra ferramenta de modelo para renderizar a saída da página. Caso contrário, o gerenciamento da edição e parametrização de HTML provavelmente fará com que o trabalho com o HTTP pareça noughts-n-crosses. Naturalmente tudo depende de quão flexível você precisa ser. Se é uma máquina de FAX com menus, pode ser muito simples. Quanto mais interações, maisespessa ” sua estrutura precisa ser. Boa pergunta, boa sorte!

Era uma vez eu estava procurando por algo semelhante – um servidor HTTP leve, mas totalmente funcional, que eu poderia facilmente incorporar e personalizar. Eu encontrei dois tipos de soluções possíveis:

  • Servidores completos que não são tão leves ou simples (para uma definição extrema de peso leve).
  • Servidores realmente leves que não são exatamente servidores HTTP, mas exemplos glorificados de ServerSocket que não são nem remotamente compatíveis com RFC e não suportam a funcionalidade básica comumente necessária.

Então … eu me propus a escrever JLHTTP – O servidor HTTP leve de Java .

Você pode incorporá-lo em qualquer projeto como um único arquivo de origem (se bem que longo) ou como um jarro de ~ 50K (~ 35K despojado) sem dependencies. Ele se esforça para ser compatível com RFC e inclui extensa documentação e muitos resources úteis, mantendo o inchaço ao mínimo.

As características incluem: hosts virtuais, arquivo servindo de disco, mapeamentos de tipo mime via arquivo mime.types padrão, geração de índice de diretório, arquivos de boas vindas, suporte para todos os methods HTTP, ETags condicionais e suporte de header If-*, codificação de transferência em partes, gzip / deflate compactação, HTTPS básico (como fornecido pela JVM), conteúdo parcial (continuação de download), manipulação de dados multipart / formulário para uploads de arquivos, vários manipuladores de contexto via API ou annotations, análise de parâmetros (string de consulta ou x-www-form-urlencoded corpo), etc.

Espero que os outros achem útil 🙂

Um servidor web muito básico escrito em java pode ser encontrado aqui http://library.sourcerabbit.com/v/?id=19

Spark é o mais simples, aqui está um guia de início rápido: http://sparkjava.com/

É possível criar um httpserver que forneça suporte básico para servlets J2EE com apenas o JDK e a API do servlet em apenas algumas linhas de código.

Eu achei isso muito útil para servlets de teste de unidade, já que ele começa muito mais rápido do que outros containers leves (usamos o jetty para produção).

A maioria dos httpservers muito leves não fornece suporte para servlets, mas nós precisamos deles, então eu pensei em compartilhar.

O exemplo abaixo fornece suporte a servlet básico ou lança e UnsupportedOperationException para coisas ainda não implementadas. Ele usa o com.sun.net.httpserver.HttpServer para suporte 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()); } } 

Eu recomendo fortemente olhar para o Simple , especialmente se você não precisar dos resources do Servlet, mas simplesmente acessar os objects request / reponse. Se você precisa de REST você pode colocar Jersey em cima dela, se você precisa produzir HTML ou similar, existe o Freemarker. Eu realmente amo o que você pode fazer com essa combinação, e há relativamente pouca API para aprender.

Você também pode dar uma olhada em algumas estruturas de aplicativos da NIO, como:

  1. Netty: http://jboss.org/netty
  2. Apache Mina: http://mina.apache.org/ ou seu subprojeto AsyncWeb: http://mina.apache.org/asyncweb/

Este código é melhor que o nosso, você só precisa adicionar 2 libs: javax.servelet.jar e org.mortbay.jetty.jar .

Píer da Classe:

 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 Simples . É um servidor embutido bastante simples, com suporte embutido para uma grande variedade de operações. Eu particularmente adoro o seu modelo de threading ..

Surpreendente!

Confira takes . Olhe para https://github.com/yegor256/takes para informações rápidas

Como sobre o projeto Apache Commons HttpCore ?

Do site: … Objetivos do HttpCore

  • Implementação dos aspectos mais fundamentais do transporte HTTP
  • Equilíbrio entre bom desempenho e clareza e expressividade da API
  • Pegada de memory pequena (previsível)
  • Biblioteca auto-contida (sem dependencies externas além do JRE)

Você pode escrever um servidor Java Jetty incorporado bastante simples.

Embedded Jetty significa que o servidor (Jetty) foi enviado junto com o aplicativo, em vez de implantar o aplicativo no servidor Jetty externo.

Portanto, se na abordagem não integrada seu webapp for construído no arquivo WAR que foi implantado em algum servidor externo ( Tomcat / Jetty / etc), no Jetty incorporado, você grava o webapp e instancia o servidor jetty na mesma base de código.

Um exemplo de servidor Java Jetty incorporado que você pode clonar e usar: https://github.com/stas-slu/embedded-jetty-java-server-example

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

Esta API cria um servidor http usando sockets. Detalhes:
1. Recebe solicitação do navegador como texto
2.Parses-lo para recuperar informações url, método, atributos, etc.
3.Cria resposta dinâmica usando o mapeamento de URL definido
4. Envia a resposta ao navegador.

Por exemplo, aqui está como o construtor na class “Response.java” converte uma resposta bruta em uma resposta http:

resposta pública (String resp) {
Data date = new Date ();
String start = “HTTP / 1.1 200 OK \ r \ n”;
String header = “Data:” + date.toString () + “\ r \ n”;
header + = “Tipo de conteúdo: text / html \ r \ n”;
header + = “Content-length:” + resp.length () + “\ r \ n”;
header + = “\ r \ n”;
this.resp = iniciar + header + resp;
}