Java 中尝试将 HTTP 响应从服务器转发到浏览器。但是,当我在浏览器中打开网站时,结果是 'octet-stream'
Trying to forward a HTTP responce from a server to a browser in Java. But, when I open the site in the browser, the result is 'octet-stream'
我有一个与 Web 浏览器打开的套接字,我的应用程序用作代理,我已经收集了 Web 浏览器发出的 HTTP 请求,并为该网站打开了一个与远程服务器的套接字。在这种情况下,我连接到 www.neverssl.com 的远程服务器,这是一个 HTTP(不是 HTTPS)连接:
InetAddress addr = InetAddress.getByName(serverAddress);
Socket remoteServerSocket = new Socket(addr, 80);
然后我告诉浏览器连接已经建立:
browserClient.getOutputStream().write(CONNECTION_ESTABLISHED.getBytes());
browserClient.getOutputStream().flush();
fullHTTPRequest 只是我发送到相应服务器的典型 HTTP 请求,我将在下面包含传递给它的实际字符串:
remoteServerSocket.getOutputStream().write(fullHTTPRequest.getBytes());
remoteServerSocket.getOutputStream().flush();
现在我只是从一个输入流中读取并将其传递到输出流(即远程服务器到网络浏览器):
byte[] buffer = new byte[4096];
int read;
do {
read = remoteServerSocket.getInputStream().read(buffer);
if (read > 0) {
browserClient.getOutputStream().write(buffer, 0, read);
if (remoteServerSocket.getInputStream().available() < 1) {
browserClient.getOutputStream().flush();
}
}
} while (read >= 0);
上面提到的完整字符串 HTTP 请求(我仔细检查了 \r\n 是所有的行尾, \r\n\r\n 出现在整个块之后:
GET http://www.neverssl.com/ HTTP/1.1
Host: www.neverssl.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.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
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1
并且(在更改我的程序以便在控制台上打印出响应之后),我可以看到这就是上面读取的 do-while 循环在浏览器输出流中产生的内容:
HTTP/1.1 200 OK
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
Last-Modified: Thu, 19 Nov 2020 22:29:21 GMT
Server: AmazonS3
Content-Encoding: gzip
Date: Sun, 14 Mar 2021 01:21:37 GMT
ETag: W/"e8bb9152091d61caa9d69fed8c4aebc6"
Vary: Accept-Encoding
X-Cache: Hit from cloudfront
Via: 1.1 8dcd559356fc30961462110a6153f8b2.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: DUB2-C1
X-Amz-Cf-Id: AiIx_Z1GbMae5ssJOV9IsWNf3zcyMkgp1BP2wjKM0-KwKLjUSGrOZg==
Age: 41501
4b8
ヒ [a lot of gibberish characters after this, which I'm assuming is the HTML from the website in some form, I just don't know what]
所以在这一切之后,我 expecting/hoping 可以在我的网络浏览器中获得一个正常的 HTML 网页。但是相反,打开网页让我可以选择下载 'octet-stream',这显然对我不利。我不明白为什么我的浏览器上没有正常的 HTTP 页面。我也尝试过分别为 .getInputStream() 使用 BufferedReaders 和为 .getOutputStream() 使用 BufferedWriters,以便它们生成字符而不是字节,但它似乎没有任何好处。有人能给我指出正确的方向吗?
Then I tell the browser that connection has been established:
您似乎混淆了用于 https://
URL 的 HTTP CONNECT 请求的响应与普通 HTTP 代理请求的响应。虽然您显然有一个普通的 http://
连接,但您应用了仅对 https://
连接有效的语义,这是错误的。
使用 CONNECT,客户端向代理发送 CONNECT 请求,代理建立到给定服务器的连接,然后接受 CONNECT 请求(即 CONNECTION_ESTABLISHED)。之后代理将只转发客户端和服务器之间的任何数据。
使用普通的 HTTP 代理请求,代理将通过更改 absolute URL in the request to an absolute path调整请求。这个修改后的请求将被转发到服务器。 代理不会对客户端请求发出自己的响应。代理只会将从服务器收到的响应发送给客户端。
在您的代码中,CONNECTION_ESTABLISHED 被错误地发送到普通 HTTP 代理请求。这不是预期的,将被解释为来自服务器的 HTTP 响应 header,因此真正的 HTTP 响应 header 和 body 将被错误地一起解释为 HTTP 响应 body.由于在错误的 HTTP 响应 header(即 CONNECTION_ESTABLISHED)中没有给出 Content-Type
,它只会猜测它可能是什么,在这种情况下它会猜测 application/octet-stream
基本上意思是“未知的二进制数据”。
我有一个与 Web 浏览器打开的套接字,我的应用程序用作代理,我已经收集了 Web 浏览器发出的 HTTP 请求,并为该网站打开了一个与远程服务器的套接字。在这种情况下,我连接到 www.neverssl.com 的远程服务器,这是一个 HTTP(不是 HTTPS)连接:
InetAddress addr = InetAddress.getByName(serverAddress);
Socket remoteServerSocket = new Socket(addr, 80);
然后我告诉浏览器连接已经建立:
browserClient.getOutputStream().write(CONNECTION_ESTABLISHED.getBytes());
browserClient.getOutputStream().flush();
fullHTTPRequest 只是我发送到相应服务器的典型 HTTP 请求,我将在下面包含传递给它的实际字符串:
remoteServerSocket.getOutputStream().write(fullHTTPRequest.getBytes());
remoteServerSocket.getOutputStream().flush();
现在我只是从一个输入流中读取并将其传递到输出流(即远程服务器到网络浏览器):
byte[] buffer = new byte[4096];
int read;
do {
read = remoteServerSocket.getInputStream().read(buffer);
if (read > 0) {
browserClient.getOutputStream().write(buffer, 0, read);
if (remoteServerSocket.getInputStream().available() < 1) {
browserClient.getOutputStream().flush();
}
}
} while (read >= 0);
上面提到的完整字符串 HTTP 请求(我仔细检查了 \r\n 是所有的行尾, \r\n\r\n 出现在整个块之后:
GET http://www.neverssl.com/ HTTP/1.1
Host: www.neverssl.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.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
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1
并且(在更改我的程序以便在控制台上打印出响应之后),我可以看到这就是上面读取的 do-while 循环在浏览器输出流中产生的内容:
HTTP/1.1 200 OK
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
Last-Modified: Thu, 19 Nov 2020 22:29:21 GMT
Server: AmazonS3
Content-Encoding: gzip
Date: Sun, 14 Mar 2021 01:21:37 GMT
ETag: W/"e8bb9152091d61caa9d69fed8c4aebc6"
Vary: Accept-Encoding
X-Cache: Hit from cloudfront
Via: 1.1 8dcd559356fc30961462110a6153f8b2.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: DUB2-C1
X-Amz-Cf-Id: AiIx_Z1GbMae5ssJOV9IsWNf3zcyMkgp1BP2wjKM0-KwKLjUSGrOZg==
Age: 41501
4b8
ヒ [a lot of gibberish characters after this, which I'm assuming is the HTML from the website in some form, I just don't know what]
所以在这一切之后,我 expecting/hoping 可以在我的网络浏览器中获得一个正常的 HTML 网页。但是相反,打开网页让我可以选择下载 'octet-stream',这显然对我不利。我不明白为什么我的浏览器上没有正常的 HTTP 页面。我也尝试过分别为 .getInputStream() 使用 BufferedReaders 和为 .getOutputStream() 使用 BufferedWriters,以便它们生成字符而不是字节,但它似乎没有任何好处。有人能给我指出正确的方向吗?
Then I tell the browser that connection has been established:
您似乎混淆了用于 https://
URL 的 HTTP CONNECT 请求的响应与普通 HTTP 代理请求的响应。虽然您显然有一个普通的 http://
连接,但您应用了仅对 https://
连接有效的语义,这是错误的。
使用 CONNECT,客户端向代理发送 CONNECT 请求,代理建立到给定服务器的连接,然后接受 CONNECT 请求(即 CONNECTION_ESTABLISHED)。之后代理将只转发客户端和服务器之间的任何数据。
使用普通的 HTTP 代理请求,代理将通过更改 absolute URL in the request to an absolute path调整请求。这个修改后的请求将被转发到服务器。 代理不会对客户端请求发出自己的响应。代理只会将从服务器收到的响应发送给客户端。
在您的代码中,CONNECTION_ESTABLISHED 被错误地发送到普通 HTTP 代理请求。这不是预期的,将被解释为来自服务器的 HTTP 响应 header,因此真正的 HTTP 响应 header 和 body 将被错误地一起解释为 HTTP 响应 body.由于在错误的 HTTP 响应 header(即 CONNECTION_ESTABLISHED)中没有给出 Content-Type
,它只会猜测它可能是什么,在这种情况下它会猜测 application/octet-stream
基本上意思是“未知的二进制数据”。