Java 中的简单 Web 代理

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18896465/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 12:03:57  来源:igfitidea点击:

Simple web proxy in Java

javasocketsproxystream

提问by Mkl Rjv

I am trying to write a simple web proxy in java which accepts both GET and POST requests. I wrote the following code:

我正在尝试用 Java 编写一个简单的 Web 代理,它接受 GET 和 POST 请求。我写了以下代码:

import java.net.*;
import java.io.*;
import java.nio.CharBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;

public class InterceptionProxy2 {

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = null;
        boolean listening = true;
        int port = 1234;
        try {
            serverSocket = new ServerSocket(port);
        } catch (IOException e) {
            System.out.println("Port Error");
            System.exit(-1);
        }
        while (listening) {
            new ProxyThread2(serverSocket.accept()).start();
        }
        serverSocket.close();
    }
}

class ProxyThread2 extends Thread {

    private Socket clientSocket = null;
    private Socket serverSocket = null;

    public ProxyThread2(Socket socket) {
        super("ProxyThread2");
        this.clientSocket = socket;
    }

    public void run() {
        //Stream to put data to the browser
        PrintWriter outGoing = null;
        try {
            outGoing = new PrintWriter(clientSocket.getOutputStream(), true);

            //Stream to get data from the browser
            BufferedReader inComing = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

            String incomingRequest;
            String url = "";
            String request = "";
            String response = "";
            //Take the incoming request
            char[] buf = new char[8196];        //8196 is the default max size for GET requests in Apache
            int bytesRead = inComing.read(buf);   //BytesRead need to be calculated if the char buffer contains too many values
            request = new String(buf, 0, bytesRead);

            System.out.println("Request");
            System.out.println(request);

            //Create a new socket for connecting to destination server
            serverSocket = new Socket("localhost", 80);
            PrintWriter pOut = new PrintWriter(serverSocket.getOutputStream(), true);

            //Reader for response from destination server
            BufferedReader pIn = new BufferedReader(new InputStreamReader(serverSocket.getInputStream()));

            //Put data into the new socket(to the apache server) and receive its output
            pOut.print(request);
            pOut.flush();
            bytesRead = pIn.read(buf);

            //Check if data is read
            if (bytesRead > 0) {
                response = new String(buf, 0, bytesRead);
            }
            System.out.println("Response");
            System.out.println(response);

            //Put data back into the original client socket
            outGoing.write(response);
        } catch (IOException ex) {
            Logger.getLogger(ProxyThread2.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            outGoing.close();
        }
    }
}

The system properly prints the request and response as output, but, the proxy does not provide the reply back to the browser. Is there anything wrong with the outGoing stream definition? Or should I create a new socket to send data back to the browser?

系统正确地将请求和响应打印为输出,但是,代理不向浏览器提供回复。outGoing 流定义有什么问题吗?或者我应该创建一个新的套接字来将数据发送回浏览器?

采纳答案by Paul Vargas

You don't need to create another instance of java.net.ServerSocket. Because you must connect to port 80, you are a client.

您不需要创建另一个java.net.ServerSocket. 因为您必须连接到端口80,所以您是一个客户端

Socket socket = new Socket("localhost", 80);

e.g.:

例如:

class ProxyThread extends Thread {

    private final Socket clientSocket;

    public ProxyThread(Socket socket) {
        this.clientSocket = socket;
    }

    public void run() {
        try {
            // Read request
            InputStream incommingIS = clientSocket.getInputStream();
            byte[] b = new byte[8196];
            int len = incommingIS.read(b);

            if (len > 0) {
                System.out.println("REQUEST"
                        + System.getProperty("line.separator") + "-------");
                System.out.println(new String(b, 0, len));

                // Write request
                Socket socket = new Socket("localhost", 80);
                OutputStream outgoingOS = socket.getOutputStream();
                outgoingOS.write(b, 0, len);

                // Copy response
                OutputStream incommingOS = clientSocket.getOutputStream();
                InputStream outgoingIS = socket.getInputStream();
                for (int length; (length = outgoingIS.read(b)) != -1;) {
                    incommingOS.write(b, 0, length);
                }

                incommingOS.close();
                outgoingIS.close();
                outgoingOS.close();
                incommingIS.close();

                socket.close();
            } else {
                incommingIS.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                clientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

回答by garvey

Your Code working for simple text files or html. There is only one problem, only the HTTP header are text data everything in the body of the HTTP message could be simple byte data like images.

您的代码适用于简单的文本文件或 html。只有一个问题,只有 HTTP 标头是文本数据,HTTP 消息正文中的所有内容都可以是简单的字节数据,如图像。

You shouldn't use the PrintWriter and/or Strings to convert the response. You should simply forward the byte buffer you will get from the Server. Just convert the byte buffer only if you want to show yourself the HTTP message.

您不应使用 PrintWriter 和/或字符串来转换响应。您应该简单地转发将从服务器获得的字节缓冲区。仅当您想向自己显示 HTTP 消息时才转换字节缓冲区。