Java中使用Java SE API的简单HTTP服务器

有没有一种方法可以使用Java SE API在Java中创build非常基本的HTTP服务器(仅支持GET / POST),而无需编写代码手动分析HTTP请求并手动格式化HTTP响应? Java SE API很好地将HttpURLConnection中的HTTP客户端function封装起来,但有没有HTTP服务器function的模拟?

为了清楚起见,我在网上看到很多ServerSocket例子的问题是,他们自己做请求parsing/响应格式化和error handling,这是单调乏味的,容易出错的,不太可能是全面的,我试图避免这些原因。

作为我试图避免的手动HTTP操作的一个例子:

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

自Java SE 6以来, Sun Oracle JRE中内置了HTTP服务器。 com.sun.net.httpserver软件包摘要概述了相关的类,并包含示例。

下面是一个从他们的文档拷贝的开球样例,你可以在Java 6+上拷贝'n'paste'来运行它。

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

注意应该是他们的例子中的response.length()部分是坏的,应该是response.getBytes().length 。 即使如此, getBytes()方法也必须明确指定您在响应头中指定的字符集。 唉,尽pipe误入歧途,毕竟只是一个基本的开球的例子。

执行它并转到http:// localhost:8000 / test ,您将看到以下响应:

这是回应


关于使用com.sun.*类,请注意,这与一些开发人员认为的相反,绝对没有被众所周知的常见问题解答为什么开发人员不应该编写“太阳”程序包 。 这个FAQ涉及sun.* JRE(这将在不同的JRE上运行时会终止你的应用程序),而不是com.sun.*软件包内部使用的sun.*包(例如sun.misc.BASE64Encoder )。 Sun / Oracle也只是在Java SE API之上开发软件,就像其他公司一样,比如Apache等。 使用com.sun.*类时,只涉及某个Java API的实现,例如GlassFish(Java EE impl),Mojarra(JSF impl),Jersey(JAX-RS impl)等,不鼓励(但不禁止) 。

退房NanoHttpd

“NanoHTTPD是一款轻量级的HTTP服务器,专为embedded其他应用程序而devise,在改进的BSD许可下发布。

它正在Github开发,并使用Apache Maven进行构build和unit testing“

com.sun.net.httpserver解决scheme不能跨JRE移植。 最好使用javax.xml.ws中的官方webservices API来引导最小的HTTP服务器…

 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) 

编辑:这实际上工作! 上面的代码看起来像Groovy什么的。 这是我testing的Java的翻译:

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

看看“Jetty”Web服务器Jetty 。 非常棒的开源软件,似乎满足您的所有需求。

如果你坚持自己滚动然后看看“httpMessage”类。

我喜欢这个问题,因为这是一个持续创新的领域,总是需要一个轻量级服务器,特别是在小型设备中讨论embedded式服务器时。 我认为答案分为两大类。

  1. 瘦服务器 :服务器上的静态内容与最小的处理,上下文或会话处理。
  2. 小型服务器 :表面上是一个有很多类似httpD的服务器品质,占地面积很小,你可以逃脱。

虽然我可能会认为HTTP库如Jetty , Apache Http Components , Netty和其他更像是一个原始的HTTP处理设施。 标签是非常主观的,并且取决于您为小型网站提供的服务种类。 我在这个问题的精神上做了这个区分,特别是关于…的话

  • “…无需编写代码来手动分析HTTP请求并手动格式化HTTP响应…”

这些原始工具让你这样做(如其他答案中所述)。 它们并不是真正适合制作轻型,embedded式或微型服务器的现成设备。 迷你服务器是一种function,可以为您提供与function齐全的Web服务器类似的function(比如说, Tomcat ),无需花时间,体积小,性能好。 瘦服务器似乎更接近原始的措辞,只是有限的子集function,可能会让你看起来很好,但是90%的时间足够了。 我的想法是在没有额外的devise和编码的情况下,75%-89%的时间让我看起来很好。 我想如果/当你达到WAR文件的级别时,我们已经把bonsi服务器的“小型”留下来了,这看起来像一个大型服务器所做的一切。

瘦服务器选项

  • 灰熊
  • UniRest (多种语言)
  • NanoHTTPD (只有一个文件)

迷你服务器选项:

  • Spark Java …好东西可能有很多辅助结构,比如Filters,Templates等
  • MadVoc …旨在成为盆景,可能是这样的;-)

在其他要考虑的事情,我会包括authentication,validation,国际化,使用像FreeMaker或其他模板工具来呈现页面输出。 否则,pipe理HTML编辑和参数化可能会使HTTP的工作看起来像n-n-n-crosses。 当然,这一切都取决于你需要多么灵活。 如果是菜单驱动的传真机,它可以非常简单。 交互越多,你的框架就越“ ”。 好问题,祝你好运!

用java编写的非常基本的Web服务器可以在这里findhttp://library.sourcerabbit.com/v/?id=19

Spark是最简单的,下面是一个快速入门指南: http : //sparkjava.com/

曾几何时,我一直在寻找类似的东西 – 一个轻量级但全function的HTTP服务器,我可以很容易地embedded和定制。 我发现了两种潜在的解决scheme:

  • 完整的服务器并不都是轻量级或简单的(对于轻量级的极端定义)。
  • 真正轻量级的服务器不是完全的HTTP服务器,但是荣耀的ServerSocket示例甚至不是远程RFC兼容的,并且不支持常用的基本function。

所以…我着手编写JLHTTP – Java轻量级HTTP服务器 。

你可以把它作为一个单独的(如果很长的话)源代码文件embedded到任何项目中,或者作为一个〜50K的jar(大约35K除去)而不依赖。 它力求符合RFC标准,包括大量的文档和许多有用的function,同时保持最小的膨胀。

function包括:虚拟主机,从磁盘文件服务,通过标准mime.types文件的MIMEtypes映射,目录索引生成,欢迎文件,支持所有的HTTP方法,有条件ETags和If- *头支持,分块传输编码,gzip / deflate压缩,基本HTTPS(由JVM提供),部分内容(下载继续),用于file upload的多部分/表单数据处理,通过API或注释的多个上下文处理程序,参数parsing(查询string或多部分/表单数据体)等等

我希望别人觉得有用:-)

我可以强烈build议查看Simple ,特别是如果您不需要Servletfunction,只需访问请求/响应对象。 如果你需要REST,你可以把Jersey放在它的顶部,如果你需要输出HTML或类似的Freemarker。 我真的很喜欢你能用这个组合来做什么,而且学习的API也相对较less。

可以创build一个httpserver,只需几行代码就可以为JDK和servlet api提供对J2EE servlet的基本支持。

我发现这对于unit testingservlet非常有用,因为它比其他的轻量级容器(我们使用jetty进行生产)要快得多。

大多数非常轻量级的httpservers不支持servlet,但我们需要它们,所以我想我会分享。

下面的例子提供了基本的servlet支持,或者对于还没有实现的东西引发和UnsupportedOperationException。 它使用com.sun.net.httpserver.HttpServer来获得基本的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()); } } 

您也可以看看一些NIO应用程序框架,例如:

  1. Netty: http : //jboss.org/netty
  2. Apache Mina: http ://mina.apache.org/或其子项目AsyncWeb: http ://mina.apache.org/asyncweb/

这个代码比我们的更好,你只需要添加2个库: javax.servelet.jarorg.mortbay.jetty.jar

class级docker:

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

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

结帐简单 。 它是一个非常简单的embedded式服务器,内置了对各种操作的支持。 我特别喜欢它的线程模型

惊人!

退房takes 。 快速浏览https://github.com/yegor256/takes

Apache Commons HttpCore项目如何?

从网站:… HttpCore目标

  • 实现最根本的HTTP传输方面
  • 在良好的performance和API的清晰度和performance之间取得平衡
  • 内存占用小(可预测)
  • 自包含的库(JRE之外没有外部依赖)

你可以写一个非常简单的embedded式Jetty Java服务器。

Embedded Jetty意味着服务器(Jetty)与应用程序一起发货,而不是在外部Jetty服务器上部署应用程序。

因此,如果在非embedded式方法中,将Web应用程序构build到部署到某个外部服务器( Tomcat / Jetty / etc)的WAR文件中,则在embedded式Jetty中编写Web应用程序并在相同的代码库中实例化Jetty服务器。

embedded式Jetty Java服务器的一个例子,你可以使用git clone和https://github.com/stas-slu/embedded-jetty-java-server-example