首页 > 解决方案 > 在 Java 中使用套接字解析和发送 HTTP 请求的正确方法是什么?

问题描述

我正在创建一个基本的本地代理服务器,目标是接受来自我的 Web 浏览器的 http 和 https 流量,解析它以获取信息,将请求发送和接收到正确的主机,然后将其返回到 Web 浏览器。

我的网络浏览器目前有一个打开的套接字。我收到来自浏览器的 http 和 https 请求,如下所示:

HTTP:

GET http://example.com/ HTTP/1.1 
Host: example.com User-Agent:
Mozilla/5.0 (X11; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5 
Accept-Encoding: gzip, deflate
Connection: keep-alive 
Upgrade-Insecure-Requests: 1

HTTPS:

CONNECT example.com:443 HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
Proxy-Connection: keep-alive
Connection: keep-alive
Host: example.com:443

我使用以下代码从上面打开一个到“主机:”的套接字:

public void sendRequest() throws IOException{
        Socket socket = new Socket(host, port);
        //socket.getInputStream.read();
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF8"));
        BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        for(int i = 0; i < lines.size(); i++){
            out.write(lines.get(i) + "\r\n");
        }
        out.flush();
        outputReturn(in);
    }

我收到这样的回复:

public void outputReturn(BufferedReader in){
        try{
            System.out.println("\n * Response");
            String line;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
        }
        catch (IOException i){
            System.out.println(i);
        }
    }

回复是这样的:

HTTP:

* Response
HTTP/1.1 200 OK
Content-Encoding: gzip
Accept-Ranges: bytes
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Wed, 10 Apr 2019 22:53:28 GMT
Etag: "1541025663+gzip"
Expires: Wed, 17 Apr 2019 22:53:28 GMT
Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
Server: ECS (ord/4C92)
Vary: Accept-Encoding
X-Cache: HIT
Content-Length: 606

;�R�TA��0
         ��W�ri]��S�V @���1k��Z��$�6���q۽���@+���l�I�I��s�PzUe���Bf
                                                                   �'��+�&gt;���+�OF   �I4h��^@^
�ЧA�p@�M���u����������*
<�|ԅߎP���P�-�6�O��$}�Jl)ǰ_,�4yU�rQazw�r���t
                                           .�s���3�
                                                   z�_������2�Mel
                                                                 ϋ5����%�t
                                                                          뫪R���t3

��:�|�Q��]���
             V-z�|�Y3*���rKp�5th��"��C���NH����v��OOyޣ�xs�����V��$��X�6�BR�b�C��PqE���K�&lt;�  �G�כ7����E(17Vx2�US��
%   x��)�d�����e��O&�4/䤘���~��Oi�s�X�dW�7��#�u�"��y\$]j<�L�r�˻'�ɪ�Vg?Kr {=��΋]E��^x;�ƱX
                                                                                            TU��]�[�{��s+�e����9�g���]����H�4���#�KA��'�Z�����*r�
�$�G�   ��4�n�8���㊄+c���E�hA��X���������L��RIt�[4\����

HTTPS:

CONNECT getpocket.cdn.mozilla.net:443 HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
Proxy-Connection: keep-alive
Connection: keep-alive
Host: getpocket.cdn.mozilla.net:443


 * Response
java.net.SocketException: Connection reset

问题:

为什么我会收到来自 HTTP 请求的二进制文件?

为什么我的 HTTPS 请求没有收到任何信息?

我应该怎么做?

提前致谢。

标签: javasocketshttp

解决方案


对于您的 HTTP 请求,Content-Encodinggzip. 二进制文件是 gzip 压缩的数据。

对于您的 HTTPS 请求,您没有进行 SSL/TLS 握手,因此服务器会断开连接。

对于 HTTP,我认为您不需要做任何事情,浏览器应该为您处理它。使用您描述的方法代理 HTTPS/SSL/TLS 没有可行的方法。


推荐阅读