如何用Java实现HTTP代理服务器
要用Java实现一个HTTP代理服务器,你可以使用Java的Socket编程来监听客户端的连接请求,并将请求转发到目标服务器。以下是一个简单的HTTP代理服务器的实现示例:
import java.io.*;
import java.net.*;
public class SimpleHttpProxyServer {
private int port;
public SimpleHttpProxyServer(int port) {
this.port = port;
}
public void start() {
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("HTTP Proxy Server is running on port: " + port);
while (true) {
Socket clientSocket = serverSocket.accept();
new Thread(new ProxyHandler(clientSocket)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static class ProxyHandler implements Runnable {
private Socket clientSocket;
public ProxyHandler(Socket clientSocket) {
this.clientSocket = clientSocket;
}
@Override
public void run() {
try (
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
OutputStream out = clientSocket.getOutputStream()
) {
String requestLine = in.readLine();
if (requestLine == null) {
return;
}
// 解析请求行,获取请求方法、URL和HTTP版本
String[] requestParts = requestLine.split(" ");
String method = requestParts[0];
String url = requestParts[1];
// 处理CONNECT方法(用于HTTPS代理)
if ("CONNECT".equalsIgnoreCase(method)) {
handleConnect(url, out);
} else {
// 处理GET和POST方法
handleHttpRequest(url, method, in, out);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void handleConnect(String url, OutputStream out) throws IOException {
URL targetUrl = new URL(url);
String host = targetUrl.getHost();
int port = targetUrl.getPort() == -1 ? 443 : targetUrl.getPort();
Socket targetSocket = new Socket(host, port);
out.write(("HTTP/1.1 200 Connection Establishedrnrn").getBytes());
// 将客户端和目标服务器的socket连接起来
Thread clientToTarget = new Thread(() -> {
try {
transferData(clientSocket.getInputStream(), targetSocket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
});
Thread targetToClient = new Thread(() -> {
try {
transferData(targetSocket.getInputStream(), clientSocket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
});
clientToTarget.start();
targetToClient.start();
}
private void handleHttpRequest(String url, String method, BufferedReader in, OutputStream out) throws IOException {
URL targetUrl = new URL(url);
String host = targetUrl.getHost();
int port = targetUrl.getPort() == -1 ? 80 : targetUrl.getPort();
HttpURLConnection connection = (HttpURLConnection) targetUrl.openConnection();
connection.setRequestMethod(method);
connection.setDoOutput(true);
// 设置请求头
for (int i = 1; ; i++) {
String header = in.readLine();
if (header == null || header.isEmpty()) {
break;
}
if ("Host".equalsIgnoreCase(header.split(":")[0])) {
connection.setRequestProperty("Host", header.split(":")[1]);
}
}
// 发送请求体
if ("POST".equalsIgnoreCase(method)) {
String contentType = connection.getContentType();
out.write(("POST " + url + " HTTP/1.1rn").getBytes());
out.write(("Host: " + host + "rn").getBytes());
out.write(("Content-Type: " + contentType + "rn").getBytes());
out.write(("Content-Length: " + connection.getContentLength() + "rn").getBytes());
out.write("rn".getBytes());
byte[] body = new byte[connection.getContentLength()];
in.readFully(body);
out.write(body);
} else {
out.write(("GET " + url + " HTTP/1.1rn").getBytes());
out.write(("Host: " + host + "rn").getBytes());
out.write("rn".getBytes());
}
// 读取响应并转发给客户端
transferData(connection.getInputStream(), out);
// 关闭连接
connection.disconnect();
}
private void transferData(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
}
}
public static void main(String[] args) {
int port = 8080; // 代理服务器监听的端口
SimpleHttpProxyServer proxyServer = new SimpleHttpProxyServer(port);
proxyServer.start();
}
}
说明:
- 监听端口:代理服务器在指定的端口上监听客户端的连接请求。
- 处理连接:当客户端连接时,创建一个新的线程来处理该连接。
- 解析请求:读取并解析HTTP请求行和请求头,获取请求方法、URL和HTTP版本。
- 处理CONNECT方法:用于HTTPS代理,建立与目标服务器的TCP连接,并将客户端和目标服务器的socket连接起来。
- 处理GET和POST方法:读取请求体并发送给目标服务器,然后将目标服务器的响应转发给客户端。
- 数据传输:使用
transferData方法在两个socket之间传输数据。
注意事项:
- 这个示例是一个简单的HTTP代理服务器,没有处理所有的HTTP方法和请求头。
- 对于HTTPS代理,需要处理CONNECT方法,并建立TLS连接。
- 实际应用中,可能需要添加更多的功能和错误处理,例如缓存、日志记录、认证等。
你可以根据需要扩展这个示例,以满足更复杂的需求。