我已经用Java创建了一个代理服务器(参见下面的代码),问题是,我从网络服务器收到响应,但是我的代理客户端处理客户端(浏览器)之间的连接以及与代理的服务器端创建套接字后的 Web 服务器。服务器端创建一个客户端并发送请求和套接字,然后在新线程中处理。 我有几个问题:
第一个代码是代理的客户端,第二个代码部分是代理的服务器端
- 在浏览器/代理/网络服务器之间发送数据时应该使用什么类型的流?
从流发送和接收时可以使用字符串还是应该使用某种类型的字节数组?
为什么浏览器没有从代理接收任何内容?因为我可以从控制台打印出来,但是当写入流时,浏览器中没有任何反应。
另外,为什么我需要在浏览器中单击“输入”两次才能使代理使用react?
public class Client implements Runnable { private String request; private String response; private Socket browserSocket; public Client(String request, Socket browserSocket) { this.request = request; this.response = ""; this.browserSocket = browserSocket; } @Override public void run() { /* Send request to web server and get the response. */ this.request = Client.modifyHttpHeader("Connection", "close", this.request); String hostName = Client.getHttpHeader("Host", this.request); if (!hostName.isEmpty()) { try { /* Send request to the web-server. */ Socket socket = new Socket(hostName, 80); OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream()); PrintWriter pw = new PrintWriter(osw); pw.write(this.request); pw.flush(); System.out.println("---S:REQUEST---"); System.out.println(this.request); System.out.println("---S:REQUEST---"); /* Receive the response from the web-server. */ BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); String response = ""; int tmpData; while ((tmpData = br.read()) != -1) { response += (char)tmpData; } this.response = response; socket.close(); /* Close the socket between client-side and web-server. */ /* Send the response back to the browser. */ OutputStreamWriter oswbrowser = new OutputStreamWriter(this.browserSocket.getOutputStream()); PrintWriter pwBrowser = new PrintWriter(oswbrowser); pwBrowser.write(this.response); pwBrowser.flush(); pwBrowser.close(); this.browserSocket.close(); /* Close the socket between client-side and browser. */ System.out.println("---C:RESPONSE---"); System.out.println(this.response); System.out.println("---C:RESPONSE---"); } catch (Exception e) { System.err.println(e.getMessage()); e.printStackTrace(); } } } public String getHttpResponse() { return this.response; } /** * * @param header * The name of the HTTP header. Example: "GET". * Note: Header name is case sensitive. * @param request * The HTTP message. * @return * On success: The value following the HTTP header ": " (colon and whitespace). * On failure: Empty string. */ public static String getHttpHeader(String header, String request) { int startHeaderIndex = request.indexOf(header) + header.length(); int endHeaderIndex = request.indexOf('\n', startHeaderIndex); /* Could not find the searched header. */ if (startHeaderIndex == -1 || endHeaderIndex == -1) return ""; /* Add 2 to remove ':' and ' '(white space). Decrement 1 to exclude '\r' and '\n' */ return request.substring(startHeaderIndex + 2, endHeaderIndex - 1); } /** * * @param header * The name of the HTTP header. Example: "Connection" * Note: The header is case sensitive. * @param value * The new value you want to put. Example: "Close" * @param request * The HTTP message. * @return * On success: A new HTTP request with the modified header value. * On failure: Empty string. * */ public static String modifyHttpHeader(String header, String value, String request) { int startHeaderIndex = request.indexOf(header) + header.length(); int endHeaderIndex = request.indexOf('\n', startHeaderIndex); /* Could not find the searched header. */ if (startHeaderIndex == -1 || endHeaderIndex == -1) return ""; String newRequest = ""; /* Copy all characters including ':' and ' ' (whitespace) */ for (int i = 0; i < startHeaderIndex + 2; i++) { newRequest += request.charAt(i); } newRequest += value; newRequest += "\r\n"; /* Add the rest of the request. */ for (int i = endHeaderIndex + 1; i < request.length(); i++) { newRequest += request.charAt(i); } return newRequest; } } public class Server { public static void main(String[] args) throws Exception{ /* Receiving and parsing port number from command line arguments. */ int ssPort = 0; if (args.length > 1 || args.length == 0){ System.err.println("Only one argument allowed; port number (int)."); System.exit(1); } else { try { ssPort = Integer.parseInt(args[0]); } catch(NumberFormatException exception) { System.err.println("Argument \"" + args[0] + "\" must be a number."); System.exit(1); } } ServerSocket serverSocket = new ServerSocket(ssPort); /* Creating the server socket. */ System.out.println("Proxy running on port: " + ssPort); while(true) { System.out.println("Waiting for client..."); Socket clientSocket = serverSocket.accept(); /* Listening for connections. */ BufferedReader bReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); String request = ""; int tmpData; while ((tmpData = bReader.read()) != -1) { request += (char)tmpData; } Client clientObject = new Client(request, clientSocket); Thread clientThread = new Thread(clientObject); clientThread.start(); /* Start the client thread. */ } }
}
最佳答案
把一切都扔掉。这不是代理的编写方式。 HTTP 代理应该:
- 从下游客户端读取一行行,以确定连接到上游的对象,无需缓冲。
- 连接上游。
- 如果 (2) 失败,则向下游发送适当的 HTTP 响应并关闭连接。
- 否则,开始同时在两个方向复制字节。
您不应该尝试组装整个请求,甚至是 header ,并且上面的“字节”和“同时”一词至关重要。请注意,您不必对 HTTP keep-alive、Connection
header 、HTTPS 等执行任何操作。
关于Java 代理不会将任何内容发送回浏览器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43123656/