是否有一种方法可以使用Java SE API在Java中创建一个非常基本的HTTP服务器(只支持GET/POST),而不需要编写代码手动解析HTTP请求和手动格式化HTTP响应?Java SE API在HttpURLConnection中很好地封装了HTTP客户机功能,但是是否有类似的HTTP服务器功能呢?
需要明确的是,我在网上看到的许多ServerSocket示例的问题是,它们自己进行请求解析/响应格式化和错误处理,这很乏味,容易出错,而且不太全面,出于这些原因,我试图避免使用它。
是否有一种方法可以使用Java SE API在Java中创建一个非常基本的HTTP服务器(只支持GET/POST),而不需要编写代码手动解析HTTP请求和手动格式化HTTP响应?Java SE API在HttpURLConnection中很好地封装了HTTP客户机功能,但是是否有类似的HTTP服务器功能呢?
需要明确的是,我在网上看到的许多ServerSocket示例的问题是,它们自己进行请求解析/响应格式化和错误处理,这很乏味,容易出错,而且不太全面,出于这些原因,我试图避免使用它。
当前回答
检查拍摄。查看https://github.com/yegor256/takes获取快速信息
其他回答
这是我简单的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进行构建和单元测试。”
以上所有的回答关于单主线程请求处理器的细节。
设置:
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();
}
}
}
从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文件等其他资产)放在该目录中来显示它们。
示例(我把这些放在桌面上,上面指定为我的根目录):
index . 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客户端,请参阅Java 11新HTTP客户端API。
试试这个https://github.com/devashish234073/Java-Socket-Http-Server/blob/master/README.md
这个API使用套接字创建了一个HTTP服务器。
它以文本的形式从浏览器获取请求 解析它来检索URL信息、方法、属性等。 使用定义的URL映射创建动态响应 将响应发送到浏览器。
例如,下面是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;
}