gpt4 book ai didi

java - 在 Java 中通过 Socket 处理 POST 请求

转载 作者:可可西里 更新时间:2023-11-01 16:55:56 24 4
gpt4 key购买 nike

我正在尝试使用套接字在 Java 中处理一个简单的 POST 请求。我可以毫无问题地接收请求 header 并响应请求,但我肯定无法获取请求正文。

我在某处读到我需要打开第二个 InputStream 才能实现此目的,但这对我来说真的没有意义。关于如何获取请求正文,您有什么提示吗?

这就是我用来获取标题的基本方法:

BufferedReader in = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));

char[] inputBuffer = new char[INPUT_BUFFER_LENGTH];

int inputMessageLength = in.read(inputBuffer, 0,
INPUT_BUFFER_LENGTH);

String inputMessage = new String(inputBuffer, 0, inputMessageLength);

所以,我收到的消息是这样的:

POST / HTTP/1.1
User-Agent: Java/1.8.0_45
Host: localhost:5555
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

但是获取不到POST请求的参数。

编辑:

所以结果证明我的 INPUT_BUFFER_LENGTH 足够高(我知道,真丢人)。因此,当它工作时,我将我的 ServerSocket 更改为 SSLServerSocket 并再次尝试从 Java 发送带有 HttpsUrlConnection 的请求,现在我遇到了同样的问题再次(已经检查了缓冲区),得到这样的东西:

POST / HTTP/1.1
User-Agent: Java/1.8.0_45
Host: localhost:5555
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
Content-type: application/x-www-form-urlencoded
Content-Length: 128

*Missing Body*

事实证明,我只有在使用 Java 客户端发送请求时才会收到此消息 - 从 Chrome 发送请求等工作正常 - 所以我假设我的代码有问题。这是我用来发送请求的内容:

System.setProperty("javax.net.ssl.trustStore", ...);
System.setProperty("javax.net.ssl.trustStorePassword", ...);

SSLSocketFactory socketFactory = (SSLSocketFactory) SSLSocketFactory
.getDefault();

String url = "https://...";
URL obj = new URL(url);
HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();

HttpsURLConnection.setDefaultSSLSocketFactory(socketFactory);

con.setRequestMethod("POST");
con.setDoOutput(true);

OutputStreamWriter writer = new OutputStreamWriter(con.getOutputStream());

writer.write(*Some String*);
writer.flush();
writer.close();

关于我的代码可能有什么问题的任何提示?

最佳答案

您显示的代码不是读取 HTTP 请求的正确方法。

首先,Java 有自己的 HttpServerHttpsServer类。您应该考虑使用它们。

否则,您必须手动实现 HTTP 协议(protocol)。您需要逐行读取输入,直到到达指示请求 header 结尾的空行,然后查看您已读取的 header ,特别是 Transfer-EncodingContent-Length header ,根据 RFC 2616 Section 4.4 了解如何读取请求的剩余字节:

4.4 Message Length

The transfer-length of a message is the length of the message-body asit appears in the message; that is, after any transfer-codings havebeen applied. When a message-body is included with a message, thetransfer-length of that body is determined by one of the following(in order of precedence):

  1. Any response message which "MUST NOT" include a message-body (suchas the 1xx, 204, and 304 responses and any response to a HEADrequest) is always terminated by the first empty line after theheader fields, regardless of the entity-header fields present inthe message.
  1. If a Transfer-Encoding header field (section 14.41) is present andhas any value other than "identity", then the transfer-length isdefined by use of the "chunked" transfer-coding (section 3.6),unless the message is terminated by closing the connection.
  1. If a Content-Length header field (section 14.13) is present, itsdecimal value in OCTETs represents both the entity-length and thetransfer-length. The Content-Length header field MUST NOT be sentif these two lengths are different (i.e., if a Transfer-Encodingheader field is present). If a message is received with both aTransfer-Encoding header field and a Content-Length header field,the latter MUST be ignored.
  1. If the message uses the media type "multipart/byteranges", and theransfer-length is not otherwise specified, then this self-elimiting media type defines the transfer-length. This media typeUST NOT be used unless the sender knows that the recipient can arseit; the presence in a request of a Range header with ultiple byte-range specifiers from a 1.1 client implies that the lient can parsemultipart/byteranges responses.

A range header might be forwarded by a 1.0 proxy that does notunderstand multipart/byteranges; in this case the server MUSTdelimit the message using methods defined in items 1,3 or 5 ofthis section.

  1. By the server closing the connection. (Closing the connectioncannot be used to indicate the end of a request body, since thatwould leave no possibility for the server to send back a response.)

For compatibility with HTTP/1.0 applications, HTTP/1.1 requestscontaining a message-body MUST include a valid Content-Length headerfield unless the server is known to be HTTP/1.1 compliant. If arequest contains a message-body and a Content-Length is not given,the server SHOULD respond with 400 (bad request) if it cannotdetermine the length of the message, or with 411 (length required) ifit wishes to insist on receiving a valid Content-Length.

All HTTP/1.1 applications that receive entities MUST accept the"chunked" transfer-coding (section 3.6), thus allowing this mechanismto be used for messages when the message length cannot be determinedin advance.

Messages MUST NOT include both a Content-Length header field and anon-identity transfer-coding. If the message does include a non-identity transfer-coding, the Content-Length MUST be ignored.

When a Content-Length is given in a message where a message-body isallowed, its field value MUST exactly match the number of OCTETs inthe message-body. HTTP/1.1 user agents MUST notify the user when aninvalid length is received and detected.

尝试更像这样的东西(半伪代码):

String readLine(BufferedInputStream in)
{
// HTTP carries both textual and binary elements.
// Not using BufferedReader.readLine() so it does
// not "steal" bytes from BufferedInputStream...

// HTTP itself only allows 7bit ASCII characters
// in headers, but some header values may be
// further encoded using RFC 2231 or 5987 to
// carry Unicode characters ...

InputStreamReader r = new InputStreamReader(in, StandardCharsets.US_ASCII);
StringBuilder sb = new StringBuilder();
char c;
while ((c = r.read()) >= 0) {
if (c == '\n') break;
if (c == '\r') {
c = r.read();
if ((c < 0) || (c == '\n')) break;
sb.append('\r');
}
sb.append(c);
}
return sb.toString();
}

...

BufferedInputStream in = new BufferedInputStream(clientSocket.getInputStream());

String request = readLine(in);
// extract method, resource, and version...

String line;

do
{
line = readLine(in);
if (line.isEmpty()) break;
// store line in headers list...
}
while (true);

// parse headers list...

if (request method has a message-body) // POST, etc
{
if ((request version >= 1.1) &&
(Transfer-Encoding header is present) &&
(Transfer-Encoding != "identity"))
{
// read chunks...
do
{
line = readLine(in); // read chunk header
int size = extract value from line;
if (size == 0) break;
// use in.read() to read the specified
// number of bytes into message-body...
readLine(in); // skip trailing line break
}
while (true);

// read trailing headers...
line = readLine(in);
while (!line.isEmpty())
{
// store line in headers list, updating
// any existing header as needed...
}

// parse headers list again ...
}
else if (Content-Length header is present)
{
// use in.read() to read the specified
// number of bytes into message-body...
}
else if (Content-Type is "multipart/...")
{
// use readLine(in) and in.read() as needed
// to read/parse/decode MIME encoded data into
// message-body until terminating MIME boundary
// is reached...
}
else
{
// fail the request...
}
}

// process request and message-body as needed..

关于java - 在 Java 中通过 Socket 处理 POST 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30901173/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com