繁体   English   中英

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

[英]Simple HTTP server in Java using only Java SE API

Is there a way to create a very basic HTTP server (supporting only GET/POST) in Java using just the Java SE API, without writing code to manually parse HTTP requests and manually format HTTP responses? The Java SE API nicely encapsulates the HTTP client functionality in HttpURLConnection , but is there an analog for HTTP server functionality?

需要明确的是,我在网上看到的很多ServerSocket示例的问题是它们自己进行请求解析/响应格式化和错误处理,这很乏味,容易出错,而且不太可能全面,出于这些原因,我正试图避免它。

从 Java SE 6 开始, Sun Oracle JRE 中有一个内置的 HTTP 服务器。 com.sun.net.httpserver包摘要概述了所涉及的类并包含示例。

下面是从自己的文件copypasted(所有的人试图编辑尽管如此,因为它是一个丑陋的代码,请不要开球例子,这是一个复制粘贴,不是我的,而且你永远不应该修改报价,除非他们已经改变在原始来源)。 你可以在 Java 6+ 上复制'n'paste'n'run它。

 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()方法也必须显式指定随后在响应标头中指定的字符集。 唉,虽然对初学者有误导,但这毕竟只是一个基本的开球示例。

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

这是回应


至于使用com.sun.*类,请注意,与某些开发人员的想法相反,众所周知的常见问题解答为什么开发人员不应编写调用 'sun' Packages 的程序绝对不会禁止这样做 该常见问题解答涉及供 Oracle JRE 内部使用的sun.*包(例如sun.misc.BASE64Encoder )(因此,当您在不同的 JRE 上运行它时会杀死您的应用程序),而不是com.sun.*包。 Sun/Oracle 也只是在 Java SE API 本身之上开发软件,就像其他所有公司(例如 Apache 等)一样。 仅在涉及某个 Java API 的实现时不鼓励(但不禁止)使用com.sun.*类,例如 GlassFish(Java EE impl)、Mojarra(JSF impl)、Jersey(JAX-RS impl)等.

查看NanoHttpd

NanoHTTPD 是一个轻量级的 HTTP 服务器,设计用于嵌入其他应用程序,在修改后的 BSD 许可下发布。

它正在 Github 上开发,并使用 Apache Maven 进行构建和单元测试”

我喜欢这个问题,因为这是一个不断创新的领域,并且总是需要一个轻型服务器,尤其是在谈论小型(er)设备中的嵌入式服务器时。 我认为答案分为两大类。

  1. 瘦服务器:服务器上静态内容,处理、上下文或会话处理最少。
  2. Small-server :表面上有许多类似 httpD 的服务器质量,并且占用的空间尽可能小。

虽然我可能认为 HTTP 库如: JettyApache Http ComponentsNetty和其他更像是原始 HTTP 处理设施。 标签是非常主观的,取决于您要求为小型站点交付的内容类型。 我本着问题的精神做出这种区分,特别是关于...

  • “......无需编写代码来手动解析 HTTP 请求和手动格式化 HTTP 响应......”

这些原始工具可让您做到这一点(如其他答案中所述)。 他们并不真正适合制作轻型、嵌入式或迷你服务器的现成风格。 迷你服务器可以为您提供与全功能 Web 服务器(例如Tomcat )类似的功能,没有花里胡哨、低容量、99% 的时间性能良好。 瘦服务器似乎更接近原始措辞,只是比原始的可能具有有限的子集功能,足以让您在 90% 的时间内看起来不错。 我对原始的想法是让我在 75% - 89% 的时间里看起来不错,而无需额外的设计和编码。 我认为,如果/当您达到 WAR 文件的级别时,我们已经为 bonsi 服务器留下了“小”,看起来像大服务器所做的一切都变小了。

瘦服务器选项

迷你服务器选项:

  • Spark Java ... 使用过滤器、模板等许多辅助结构可以实现好东西。
  • MadVoc ......旨在成为盆景,很可能是这样的;-)

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

com.sun.net.httpserver解决方案不能跨 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 什么的。 这是我测试过的 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”网络服务器Jetty 出色的开源软件,似乎可以满足您的所有要求。

如果您坚持自己滚动,请查看“httpMessage”类。

曾几何时,我正在寻找类似的东西 - 一个轻量级但功能齐全的 HTTP 服务器,我可以轻松嵌入和自定义。 我发现了两种类型的潜在解决方案:

  • 不是所有轻量级或简单的完整服务器(对于轻量级的极端定义。)
  • 真正的轻量级服务器,不是完全的 HTTP 服务器,而是美化的 ServerSocket 示例,它们甚至不符合远程 RFC 标准并且不支持通常需要的基本功能。

所以...我开始编写JLHTTP - The Java Lightweight HTTP Server

您可以将它作为单个(如果很长)源文件或作为 ~50K jar(剥离 ~35K)而没有依赖项嵌入到任何项目中。 它努力与 RFC 兼容,并包含大量文档和许多有用的功能,同时将膨胀保持在最低限度。

功能包括:虚拟主机、从磁盘提供文件、通过标准 mime.types 文件进行 mime 类型映射、目录索引生成、欢迎文件、支持所有 HTTP 方法、条件 ETag 和 If-* 标头支持、分块传输编码、gzip/deflate压缩、基本 HTTPS(由 JVM 提供)、部分内容(下载继续)、文件上传的多部分/表单数据处理、通过 API 或注释的多个上下文处理程序、参数解析(查询字符串或 x-www-form-urlencoded体)等。

我希望其他人觉得它有用:-)

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

以上所有回答有关单主线程请求处理程序的详细信息。

设置:

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

允许使用执行程序服务通过多个线程提供多个请求。

所以最终代码将如下所示:

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

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

我发现这对于单元测试 servlet 非常有用,因为它比其他轻量级容器(我们使用 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

类码头:

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

    }
} 

服务端类:

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

我强烈建议您查看Simple ,特别是如果您不需要 Servlet 功能而只需访问请求/响应对象。 如果您需要 REST,您可以将 Jersey 放在上面,如果您需要输出 HTML 或类似内容,则可以使用 Freemarker。 我真的很喜欢你可以用这个组合做什么,而且需要学习的 API 相对较少。

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

太棒了!

退房takes 查看https://github.com/yegor256/takes获取快速信息

试试这个https://github.com/devashish234073/Java-Socket-Http-Server/blob/master/README.md

该 API 使用套接字创建了一个 HTTP 服务器。

  1. 它以文本形式从浏览器获取请求
  2. 解析它以检索 URL 信息、方法、属性等。
  3. 使用定义的 URL 映射创建动态响应
  4. 将响应发送到浏览器。

例如,这里是Response.java类中的构造函数如何将原始响应转换为 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;
}

Apache Commons HttpCore项目怎么样?

来自网站:... HttpCore 目标

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

Java 18开始,您可以使用 Java 标准库创建简单的 web 服务器:

class Main {
    public static void main(String[] args) {
        var port = 8000;
        var rootDirectory = Path.of("C:/Users/Mahozad/Desktop/");
        var outputLevel = OutputLevel.VERBOSE;
        var server = SimpleFileServer.createFileServer(
                new InetSocketAddress(port),
                rootDirectory,
                outputLevel
        );
        server.start();
    }
}

默认情况下,这将显示您指定的根目录的目录列表。 您可以将index.html文件(以及其他资产,如 CSS 和 JS 文件)放在该目录中以显示它们。

示例(我将这些放在桌面上,上面指定为我的目录根目录):

索引.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Java 18 Simple Web Server</title>
  <link rel="stylesheet" href="styles.css">
  <style>h1 { color: blue; }</style>
  <script src="scripts.js" defer>
    let element = document.getElementsByTagName("h1")[0];
    element.style.fontSize = "48px";
  </script>
</head>
<body>
  <h1>I'm <i>index.html</i> in the root directory.</h1>
</body>
</html>

边注

对于 Java 标准库 HTTP客户端,请参见这篇文章

您可以编写一个非常简单的嵌入式 Jetty Java 服务器。

嵌入式 Jetty 意味着服务器 (Jetty) 与应用程序一起提供,而不是在外部 Jetty 服务器上部署应用程序。

因此,如果在非嵌入式方法中您的 webapp 内置到部署到某个外部服务器( Tomcat / Jetty / 等)的 WAR 文件中,则在嵌入式 Jetty 中,您编写 webapp 并在相同的代码库中实例化码头服务器。

您可以git clone和使用的嵌入式 Jetty Java 服务器示例: https : //github.com/stas-slu/embedded-jetty-java-server-example

从 Java 11 开始,旧的com.sun.net.httpserver再次成为公共和接受的 API。您可以将它作为HttpServer类获取,作为jdk.httpserver模块的一部分提供。 https://docs.oracle.com/en/java/javase/11/docs/api/jdk.httpserver/com/sun/net/httpserver/HttpServer.html

这个类实现了一个简单的 HTTP 服务器。 HttpServer 绑定到一个 IP 地址和端口号,并在此地址上侦听来自客户端的传入 TCP 连接。 子类 HttpsServer 实现了一个处理 HTTPS 请求的服务器。

因此,除了它的局限性之外,没有理由再避免使用它。

我用它在服务器应用程序中发布控制接口。 从客户端请求中读取User-agent标头,我什至以text/plain响应curl等 CLI 工具,或者以更优雅的 HTML 方式响应任何其他浏览器。

很酷很容易。

TCP 套接字级别的非常基本的 HTTP 服务器的示例:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class NaiveHttpServer {

  public static void main(String[] args) throws IOException {
    String hostname = InetAddress.getLocalHost().getHostName();
    ServerSocket serverSocket = new ServerSocket(8089);
    while (true) {
      Socket clientSocket = serverSocket.accept();
      PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
      BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
      String s = in.readLine();
      System.out.println(s);
      while ("\r\n".equals(in.readLine())); 
      if ("GET /hostname HTTP/1.1".equals(s)) {
        out.println("HTTP/1.1 200 OK");
        out.println("Connection: close");
        out.println("Content-Type: text/plain");
        out.println("Content-Length:" + hostname.length());
        out.println();
        out.println(hostname);
      } else {
        out.println("HTTP/1.1 404 Not Found");
        out.println("Connection: close");
        out.println();    
      }
      out.flush();
    }
  }
}

该示例提供计算机的主机名。

这是我的简单网络服务器,在 JMeter 中用于测试 webhook(这就是为什么它会在收到请求后关闭并自行结束)。

import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class HttpServer {

    private static int extractContentLength(StringBuilder sb) {
        int length = 0;
        String[] lines = sb.toString().split("\\n");
        for (int i = 0; i < lines.length; i++) {
            String s = lines[i];
            if (s.toLowerCase().startsWith("Content-Length:".toLowerCase()) && i <= lines.length - 2) {
                String slength = s.substring(s.indexOf(":") + 1, s.length()).trim();
                length = Integer.parseInt(slength);
                System.out.println("Length = " + length);
                return length;
            }
        }
        return 0;
    }

    public static void main(String[] args) throws IOException {
        
        
        int port = Integer.parseInt(args[0]);
        System.out.println("starting HTTP Server on port " + port);

        StringBuilder outputString = new StringBuilder(1000);

        ServerSocket serverSocket = new ServerSocket(port);
        serverSocket.setSoTimeout(3 * 60 * 1000); // 3 minutes timeout
        while (true) {

            outputString.setLength(0); // reset buff

            Socket clientSocket = serverSocket.accept(); // blocking
            PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);

            try {

                boolean isBodyRead = false;
                int dataBuffer;
                while ((dataBuffer = clientSocket.getInputStream().read()) != -1) {

                    if (dataBuffer == 13) { // CR
                        if (clientSocket.getInputStream().read() == 10) { // LF
                            outputString.append("\n");
                        }
                    } else {
                        outputString.append((char) dataBuffer);
                    }
                    
                    // do we have Content length
                    int len = extractContentLength(outputString);
                    if (len > 0) {
                        int actualLength = len - 1; // we need to substract \r\n
                        for (int i = 0; i < actualLength; i++) {
                            int body = clientSocket.getInputStream().read();
                            outputString.append((char) body);
                        }
                        isBodyRead = true;
                        break;
                    }

                } // end of reading while

                if (isBodyRead) {
                    // response headers
                    out.println("HTTP/1.1 200 OK");
                    out.println("Connection: close");
                    out.println(); // must have empty line for HTTP
                    
                    out.flush(); 
                    out.close(); // close clients connection
                }

            } catch (IOException ioEx) {
                System.out.println(ioEx.getMessage());
            }

            System.out.println(outputString.toString());
            break; // stop server - break while true
            
        } // end of outer while true
        
        serverSocket.close();

    } // end of method

}

你可以像这样测试它:

curl -X POST -H "Content-Type: application/json" -H "Connection: close" -d '{"name": "gustinmi", "email": "gustinmi at google dot com "}' -v http://localhost:8081/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM