Servidor HTTP simples em Java usando apenas a API Java SE
Existe uma forma de criar um Servidor HTTP muito básico (suportando apenas o GET/POST) em Java usando apenas a API Java SE, sem escrever código para processar manualmente os pedidos HTTP e formatar manualmente as respostas HTTP? A API Java SE encapsula bem a funcionalidade do cliente HTTP em HttpURLConnection, mas existe um análogo para a funcionalidade do Servidor HTTP?
Só para que fique claro, o problema que tenho com muitos exemplos de ServerSocket que vi online é que eles fazem o seu próprio pedido. processamento/resposta formatação e manipulação de erros, que é tedioso, propenso a erros, e não é provável que seja abrangente, e estou tentando evitá-lo por essas razões.como um exemplo da manipulação HTTP manual que estou a tentar evitar:
Http://java.sun.com/developer/technicalArticles/Networking/Webserver/WebServercode.html
17 answers
Desde Java SE 6, há um Servidor HTTP builtin em Sun Oracle JRE. O com.sun.net.httpserver
Resumo do pacote descreve as classes envolvidas e contém exemplos.
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(); } } }
Note-se que a parte response.length()
no seu exemplo é má, deveria ter sido response.getBytes().length
. Mesmo assim, o método getBytes()
deve especificar explicitamente a codificação que você então indique no cabeçalho da resposta. Infelizmente, embora enganando-se a começar, é, afinal, apenas um exemplo básico de pontapé de saída.
Execute-o e vá para http://localhost:8000/test e verá a seguinte resposta:
Esta é a resposta
Quanto ao uso das classes com.sun.*
, note que isto é, ao contrário do que alguns programadores pensam, absolutamente não proibido pela conhecida FAQ porque os programadores não devem escrever programas que chamam 'sun' Pacotes . Essa FAQ diz respeito ao pacote sun.*
(como sun.misc.BASE64Encoder
) para uso interno pelo Oracle JRE (que assim mataria a sua aplicação quando a executasse num JRE diferente), não ao pacote com.sun.*
. Sun / Oracle também apenas desenvolver software em cima do Java SE API, como todas as outras empresas, como o Apache e assim por diante. A utilização de com.sun.*
classes só é desencorajada (mas não proibida) quando diz respeito a uma implementação de uma determinada API Java, como o GlassFish (Java EE impl), Mojarra( JSF impl), Jersey (JAX-RS impl), etc.
Check out NanoHttpd
"NanoHTTPD é um Servidor HTTP de peso leve concebido para incorporar noutras aplicações, lançado sob uma licença BSD modificada.
Está a ser desenvolvido no Github e utiliza o Apache Maven para o teste do builds & unit "
A solução com.sun.net.httpserver não é portátil entre JREs. É melhor usar a API dos webservices oficiais em javax.xml.ws para iniciar 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("<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: isto realmente funciona! O código acima parece fixe ou algo assim. Aqui está uma tradução para Java que eu 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<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);
}
}
Gosto desta pergunta porque esta é uma área onde há inovação contínua e há sempre a necessidade de ter um servidor de luz especialmente quando se fala de servidores embutidos em pequenos(er) dispositivos. Penso que as respostas se dividem em dois grandes grupos.
- Thin-server : conteúdo estático do servidor com processamento mínimo, processamento de contexto ou sessão.
- Small-server : ostensivamente a tem muitas qualidades de servidor tipo httpD com uma pegada tão pequena quanto você pode sair impune.
Enquanto eu poderia considerar bibliotecas HTTP como: Jetty, componentes de Http Apache, Netty e outros para ser mais como uma unidade de processamento HTTP raw. A rotulagem é muito subjetiva, e depende do tipo de coisas que você tem sido chamado para entregar em locais pequenos. Faço esta distinção no espírito da pergunta, em particular a observação sobre o assunto...
- "...sem gravar o código para processar manualmente os pedidos de HTTP e formatar manualmente as respostas HTTP..."
Estas ferramentas crus permitem-lhe fazer isso (como descrito em outras respostas). Eles realmente não se prestam a um estilo pronto-set-go de fazer uma luz, embutido ou mini-servidor. Um mini-servidor é algo que pode lhe dar uma funcionalidade semelhante a um servidor web de função plena (como say, Tomcat) sem sinos e assobios, baixo volume, bom desempenho 99% do tempo. Um thin-server parece mais próximo do fraseado original apenas um pouco mais do que raw talvez com uma funcionalidade de subconjunto limitada, o suficiente para fazer você parecer bom 90% do tempo. A minha ideia de raw seria fazer - me parecer bem 75% - 89% do tempo sem design extra e codificação. Eu acho que se / quando você atingir o nível de arquivos de guerra, nós deixamos o "pequeno" para os servidores bonsi que se parece com tudo o que um servidor grande faz menor.
Opções do servidor fino
Opções do Mini-servidor:
- Spark Java ... Coisas boas são possíveis com muitas construções auxiliares como filtros, modelos, etc.
- MadVoc ... objectivos ser bonsai e poderia muito bem ser tal; -)
Entre as outras coisas a considerar, eu incluiria autenticação, validação, internacionalização, usando algo como FreeMaker ou outra ferramenta de modelo para renderizar a saída da página. Gerir de outro modo o HTML edição e parametrização é provável que o trabalho com HTTP pareça com Noughts-n-crosses. Naturalmente, tudo depende de quão flexível você precisa ser. Se é uma máquina de FAX em menu, pode ser muito simples. Quanto mais interações, o ' mais espesso ' seu framework precisa ser. Boa pergunta, boa sorte!
- servidores completos que não são assim tão leves ou simples (para uma definição extrema de lightweight.)
- servidores verdadeiramente leves que não são servidores HTTP, mas exemplos glorificados ServerSocket que não são nem remotamente compatíveis com RFC e não suportam o que é normalmente necessário funcionalidade básica.
Pode incorporá-lo em qualquer projecto como um único ficheiro de código (se bem que longo), ou como um jar ~50K (~35K despojado) sem dependências. Ele se esforça para ser compatível com o RFC e inclui extensa documentação e muitas características úteis, mantendo o bloat ao mínimo.
As funcionalidades incluem: máquinas virtuais, ficheiros que servem a partir do disco, mapeamentos do tipo mime através do mime normal.tipo file, directory index generation, welcome files, support for all HTTP methods, conditional ETags and If-* header support, chunked transfer encoding, gzip/deflate compression, basic HTTPS (as provided by the JVM), partial content (download continuation), multipart/form-data handling for file uploads, multiple context handlers via API ou annotations, parameter parsing (query string or x-www-form-urlencoded body), etc.
Espero que outros achem útil.Um servidor web básico muito escrito em java pode ser encontrado aqui http://library.sourcerabbit.com/v/?id=19
Faísca é o mais simples, aqui está um guia de arranque rápido: http://sparkjava.com/
É possível criar um httpserver que fornece suporte básico para servlets J2EE com apenas o JDK e a API servlet em apenas algumas linhas de código.
[[[2]} eu achei isso muito útil para testes de unidades servlets, como ele começa muito mais rápido do que outros recipientes leves (nós usamos jetty para a produção).A maioria dos receptores httpservers muito leves não fornecem suporte para servlets, mas nós precisamos deles, então eu pensei em compartilhar.
O exemplo que se segue fornece dados básicos apoio de servlet, ou lança e Excepçãodeoperação não apoiada 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<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());
}
}
Posso recomendar vivamente que se Procure porSimple , especialmente se não precisar de capacidades de Servlet, mas simplesmente aceder aos objectos requisitados/reponse. Se você precisa de descanso você pode colocar Jersey em cima dele, se você precisa de output HTML ou similar há Freemarker. Eu realmente amo o que você pode fazer com esta combinação, e há relativamente pouca API para aprender.
Pode também dar uma vista de olhos a uma estrutura de Aplicação NIO como:
- Netty: http://jboss.org/netty
- Apache Mina: http://mina.apache.org / ou o seu subprojecto AsyncWeb: http://mina.apache.org/asyncweb/
Este código é melhor do que o nosso, só precisas de adicionar 2 libs: javax.sergelet.jar e org.mortbay.CAL.jar .
Jacto 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 Simple . é um servidor embutido bastante simples com suporte incorporado para uma grande variedade de operações. Adoro particularmente o seu modelo de rosca..
Incrível!Check out takes
. Olha para https://github.com/yegor256/takes para informação rápida
Que tal Apache Commons HttpCore project?
A partir do site:... Objectivos Do HttpCore
- implementação dos aspectos mais fundamentais do transporte HTTP
- equilíbrio entre o bom desempenho e a clareza e expressividade do API
- pequena (previsível) pegada de memória
- biblioteca autónoma (sem dependências externas para além do JRE) {[[9]}
Você pode escrever um servidor Java bastante simples embutido Jetty.
Jetty incorporado significa que o servidor (Jetty) enviado juntamente com a aplicação, em vez de implantar a aplicação no servidor de Jetty externo.
Por isso, se na aproximação não incorporada o seu webapp incorporado num ficheiro de guerra que foi enviado para algum servidor externo (Tomcat / Jetty / etc), no Jetty incorporado, você escreve o webapp e instancia o servidor de jetty na mesma base de código.
Exemplo para o servidor Jetty Java incorporado que você pode clone do git e usar: https://github.com/stas-slu/embedded-jetty-java-server-example
Tenta isto https://github.com/devashish234073/Java-Socket-Http-Server/blob/master/README.md
Esta api criou um Servidor http usando 'sockets'. Informacao:
1.It obtém o pedido do navegador como texto
2.Analisa-o para obter informações url, método ,atributos, etc.
3.Cria uma resposta dinâmica com o mapeamento de url definidos
4.Envia a resposta para o navegador.
resposta pública (String resp){
Data = nova 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.comprimento ()+ "\r\n";
header+= "\r\n"; Isto.resp=start+header+resp;
}