JAVA写HTTP代理服务器(⼀)-socket实现 HTTP代理服务器是⼀种特殊的⽹络服务,允许⼀个⽹络终端(⼀般为客户端)通过这个服务与另⼀个⽹络终端(⼀般为服务器)进⾏⾮直接的连接。⼀些⽹关、路由器等⽹络设备具备⽹络代理功能。⼀般认为代理服务有利于保障⽹络终端的隐私或安全,防⽌攻击。
HTTP 代理有分两种:
1. (即修订后的 RFC 2616,HTTP/1.1 协议的第⼀部分)描述的普通代理。这种代理扮演的是「中间⼈」⾓⾊,对于连接到它的客户
端来说,它是服务端;对于要连接的服务端来说,它是客户端。它就负责在两端之间来回传送 HTTP 报⽂。
2. (通过 Web 代理服务器⽤隧道⽅式传输基于 TCP 的协议)描述的隧道代理。它通过 HTTP 协议正⽂部分(Body)完成通讯,以 HTTP 的⽅式实现任意基于 TCP 的应⽤层协议代理。这种代理使⽤ HTTP 的 CONNECT ⽅法建⽴连接,但 CONNECT 最开始并不是 RFC 2616 - HTTP/1.1 的⼀部分,直到 2014 年发布的 HTTP/1.1 修订版中,才增加了对 CONNECT 及隧道代理的描述,详见 RFC 7231 - HTTP/1.1: Semantics and Content。
实际上这种代理早就被⼴泛实现。
HTTP代理
http请求经过代理服务器,代理服务器只要负责转发相应的http响应体就可以了。 HTTPS代理
https请求经过代理服务器,会发送⼀个CONNECT报⽂,⽤于和代理服务器建⽴隧道,如果代理服务器返回HTTP 200,则建⽴成功,后续代理服务器只要负责转发数据就⾏,实际上SSL/TLS握⼿还是发⽣在客户端和真实服务器。
思路
创建SocketServer监听端⼝,根据http请求头⽅法如果是CONNECT就是HTTPS请求否则都为HTTP请求,接着根据HOST头建⽴代理服务器与⽬标服务器的连接,然后转发数据。HTTPS请求需要特殊处理,因为CONNECT请求并不需要转发,要返回⼀个HTTP 200的响应建⽴隧道,之后才进⾏转发。
实现
//监听端⼝
ServerSocket serverSocket = new ServerSocket(port);
for (; ; ) {
new SocketHandle(serverSocket.accept()).start();
谷胱甘肽转移酶
}
static class SocketHandle extends Thread {
private Socket socket;
public SocketHandle(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
OutputStream clientOutput = null;
InputStream clientInput = null;
Socket proxySocket = null;
InputStream proxyInput = null;
OutputStream proxyOutput = null;
安南将军try {
clientInput = InputStream();
clientOutput = OutputStream();
String line;
String host = "";
LineBuffer lineBuffer = new LineBuffer(1024);
StringBuilder headStr = new StringBuilder();
//读取HTTP请求头,并拿到HOST请求头和method
while (null != (line = adLine(clientInput))) {
敌对势力System.out.println(line);
headStr.append(line + "\r\n");
if (line.length() == 0) {
break;
} else {
String[] temp = line.split(" ");
if (temp[0].contains("Host")) {
host = temp[1];
}
}
}
String type = headStr.substring(0, headStr.indexOf(" "));
//根据host头解析出⽬标服务器的host和port
String[] hostTemp = host.split(":");
host = hostTemp[0];
int port = 80;
if (hostTemp.length > 1) {
port = Integer.valueOf(hostTemp[1]);
}
//连接到⽬标服务器
proxySocket = new Socket(host, port);
proxyInput = InputStream();
proxyOutput = OutputStream();
//根据HTTP method来判断是https还是http请求
if ("CONNECT".equalsIgnoreCase(type)) {//https先建⽴隧道
clientOutput.write("HTTP/1.1 200 Connection Established\r\n\r\n".getBytes()); clientOutput.flush();
} else {//http直接将请求头转发
proxyOutput.String().getBytes());
}
//新开线程转发客户端请求⾄⽬标服务器
new ProxyHandleThread(clientInput, proxyOutput).start();
//转发⽬标服务器响应⾄客户端
while (true) {
clientOutput.ad()); }
} catch (IOException e) {
e.printStackTrace();
} finally {
if (proxyInput != null) {
try {
proxyOutput.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (proxyOutput != null) {
try {声波识别
proxyOutput.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (proxySocket != null) {
try {
proxySocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (clientInput != null) {
try {
可再生能源电力配额管理办法clientInput.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (clientOutput != null) {
try {
clientOutput.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
static class ProxyHandleThread extends Thread {
private InputStream input;
private OutputStream output;
public ProxyHandleThread(InputStream input, OutputStream output, CountDownLatch cdl) {
this.input = input;
珠海振戎公司this.output = output;
}
@Override
public void run() {
try {
while (true) {
output.ad());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
后记
以上⼀个简单的HTTP代理服务器就实现了,不过其中问题也有很多,如BIO模型的缺陷,异常处理机制。 下⼀篇会⽤netty来实现⼀个⾼性能的HTTP代理服务器。
代码托管在上,欢迎start