java - Java HTTP/HTTPS 代理服务器
问题描述
我正在编写自己的 Java 代理服务器。当我尝试使用它时,我有正确的输出(我看到所有通过代理服务器的命令),但是我想访问的任何网站都无法正常工作,并且我的浏览器中出现以下错误:ERR_TUNNEL_CONNECTION_FAILED . 我实际上不擅长网络问题,有些事情我不明白。所以,下面有我的代码,如果有人告诉我问题出在哪里,我会很高兴:
import java.io.*;
import java.net.*;
public class ProxyServer
{
private String host;
private int localPort;
private int remotePort;
private ProxyServer(String host, int localPort, int remotePort)
{
this.host=host;
this.localPort=localPort;
this.remotePort=remotePort;
}
public static void main(String[] args) throws IOException
{
new ProxyServer("localhost", 8080, 9001).start();
}
public void start() throws IOException
{
System.out.println("Starting the proxy server for "+this.host+":"+this.localPort+"...");
ServerSocket ss=new ServerSocket(this.localPort);
final byte[] request=new byte[4096];
byte[] response=new byte[4096];
while(true)
{
Socket client=null;
Socket server=null;
try
{
client=ss.accept();
final InputStream streamFromClient=client.getInputStream();
OutputStream streamToClient=client.getOutputStream();
System.out.println(new BufferedReader(new InputStreamReader(streamFromClient)).readLine());
try
{
server=new Socket(host, this.remotePort);
}
catch(IOException exc)
{
PrintWriter out=new PrintWriter(streamToClient);
out.println("Proxy server cannot connect to "+host+":"+this.remotePort+"\n"+exc);
out.flush();
client.close();
continue;
}
InputStream streamFromServer=server.getInputStream();
final OutputStream streamToServer=server.getOutputStream();
System.out.println(new BufferedReader(new InputStreamReader(streamFromServer)).readLine());
new Thread
(
()->
{
int bytesRead;
try
{
while((bytesRead=streamFromClient.read(request))!=-1)
{
streamToServer.write(request, 0, bytesRead);
streamToServer.flush();
}
}
catch(IOException exc){}
try
{
streamToServer.close();
}
catch(IOException exc){}
}
).start();
int bytesRead;
try
{
while((bytesRead=streamFromServer.read(response))!=-1)
{
streamToClient.write(response, 0, bytesRead);
streamToClient.flush();
}
}
catch(IOException exc){}
streamToClient.close();
}
catch(IOException exc)
{
System.out.println(exc.getMessage());
}
finally
{
try
{
if(server!=null) server.close();
if(client!=null) client.close();
}
catch(IOException exc){}
}
}
}
}
解决方案
您使用预定义的硬编码目标制作了简单的 tcp 代理:host:remote_port
它不是 HTTP 代理。
因此,您的解决方案应该可以在以下情况下使用:
- 您正在 localhost:9001 上运行 squid 或一些适当的 HTTP 代理。
- 并且仅将其用作 HTTP 代理(我的意思是,当您配置浏览器时,您不应该告诉它您的应用是 https 代理)。
如果您打算制作独立代理,那么您需要分析 HTTP 请求并从请求中获取主机、端口和协议,以了解您应该连接哪个服务器(包括端口)以及您应该使用哪种协议(即 http 或 https)。当浏览器直接请求服务(没有代理)时,它只发送 URI,当浏览器通过代理发送请求时,它在请求中使用完整的 URL。
所以请求中的第一行将是这样的:
GET http://google.com[:80]/blah-blah-blah HTTP/1.1
...headers here...
您的代理需要分析 URL 并从中获取主机、端口和 URI。因此,您需要解析域名并将主机连接到修改后的第一行所需的端口。它看起来像:
GET /blah-blah-blah HTTP/1.1
...headers here...
如果您使用额外的 http 代理服务器来侦听 9001 端口,请检查它是否处于运行状态。
推荐阅读
- php - 如何在 VPS 上的 phpMyAdmin 或 SSH 中创建预定事件?
- shiny - 如何按顺序执行闪亮的模块?
- node.js - 致命:无效的参考规范(Heroku nodejs)
- hadoop - Cloudera 安装期间出现错误,提示未找到在主机服务器上运行的数据库服务器
- java - LibGDX:在另一个线程中创建新的 scene2d 对象?
- mysql - 在 2 列中计算一个值的匹配项,分别计算
- typescript - nyc (istanbul) 从覆盖率报告中排除测试代码
- anaconda - Windows Anaconda Prompt 环境不显示在 Anaconda Navigator 中
- go - 如何将多个变量传递给 Go HTML 模板
- php - 几天后,如何在 PHP 中找到未来的日期?