是否有一种方法可以使用Java SE API在Java中创建一个非常基本的HTTP服务器(只支持GET/POST),而不需要编写代码手动解析HTTP请求和手动格式化HTTP响应?Java SE API在HttpURLConnection中很好地封装了HTTP客户机功能,但是是否有类似的HTTP服务器功能呢?

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


当前回答

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”web服务器Jetty。一流的开源软件,似乎可以满足您的所有要求。

如果你坚持要创建自己的类,那么可以看看“httpMessage”类。

这是我简单的web服务器,在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/

查看NanoHttpd

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

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

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

神奇的!

这个代码比我们的代码更好,你只需要添加2个库:javax. servlet .jar和org.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);
        }

    }
} 

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