当前位置: 首页 > 面试题库 >

通过Java中的套接字处理POST请求

牟波
2023-03-14
问题内容

我正在尝试使用Socket处理Java中的简单POST请求。我可以接收请求标头并毫无问题地回答请求,但是我当然无法获取请求的正文。

我读过某个地方,我需要打开第二个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协议。您需要逐行读取输入,直到到达指示请求标头末尾的空行,然后查看已读取的标头,尤其是Transfer- EncodingContent-Length标头,以了解如何读取标头的其余字节。根据RFC
2616第4.4节的
要求:

4.4消息长度

消息的传输长度是显示在消息中的消息正文的长度。也就是说,在应用了任何传输编码之后。当消息主体包含在消息中时,该主体的传输长度由以下一项确定(按优先顺序):

1.
任何“不得”包含消息正文的响应消息(例如1xx,204和304响应以及对HEAD请求的任何响应)总是由标头字段后的第一个空行终止,而不考虑实体-
邮件中的标头字段。

  1. 如果存在Transfer-Encoding头字段(第14.41节),并且具有除“
    identity”以外的任何值,则除非使用了消息终止,否则将使用“块式”传输编码(第3.6节)定义传输长度。通过关闭连接。

  2. 如果存在Content-
    Length标头字段(第14.13节),则其在OCTET中的十进制值表示实体长度和传输长度。如果这两个长度不同(即,如果存在传输编码头字段),则不得发送Content-
    Length头字段。如果接收到的消息同时具有Transfer-Encoding头域和Content-Length头域,则后者必须被忽略。

  3. 如果消息使用媒体类型“ multipart / byteranges”,并且未另外指定ransfer-
    length,则此自限制媒体类型将定义传输长度。除非发件人知道收件人可以对此媒体类型使用,否则请勿使用此媒体类型。来自1.1客户端的带有多个字节范围说明符的Range标头在请求中的存在意味着留置权可以解析multipart
    / byteranges响应。

范围标头可能由不了解多部分/字节范围的1.0代理转发。在这种情况下,服务器必须使用本节第1,3或5条中定义的方法对消息进行定界。

  1. 通过服务器关闭连接。(关闭连接不能用于指示请求主体的结束,因为这将使服务器无法发送回响应。)

为了与HTTP / 1.0应用程序兼容,除非已知服务器兼容HTTP / 1.1,否则包含消息主体的HTTP / 1.1请求必须包含有效的Content-
Length头字段。如果一个请求包含一个消息主体,并且没有给出Content-
Length,则服务器如果不能确定消息的长度,则应该以400(错误请求)响应,或者如果希望坚持则以411(要求长度)响应。收到有效的Content-
Length。

接收实体的所有HTTP / 1.1应用程序必须接受“块式”传输编码(第3.6节),因此,当无法预先确定消息长度时,允许将该机制用于消息。

消息不得同时包含Content-Length头字段和非身份转移编码。如果消息中确实包含非身份转移编码,则必须忽略Content-Length。

在允许消息正文的消息中给出Content-Length时,其字段值务必与消息正文中的OCTET数量完全匹配。当收到并检测到无效长度时,HTTP /
1.1用户代理务必通知用户。

尝试类似以下内容(半伪代码):

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..


 类似资料:
  • 问题内容: 我有2个java netbeans项目,一个是Server,另一个是Client。我已经创建了一个Message类,该类要传递给服务器,并在服务器上进行修改后以另一种方式返回给客户端。我在两个项目中都包含了Message类。我使用和传递对象。服务器和客户端之间的连接正常,并且对象通过,但在服务器上,当我从using 方法读取对象时,将其类型转换为类。但是在服务器上抛出 ClassNot

  • 问题内容: 大家好。我有一个使用ServerSocket和Socket类用Java编写的服务器。 我希望能够检测并处理断开连接,然后在必要时重新连接新客户端。 检测客户端断开连接,关闭套接字然后接受新客户端的正确步骤是什么? 问题答案: 大概是在从套接字读取数据,也许是在输入流上使用包装器,例如BufferedReader。在这种情况下,当相应的读取操作返回-1(对于原始read()调用)或为nu

  • 问题内容: 当我通过套接字发送正常的HTTP请求时,服务器不会以OK响应进行响应。我从Firefox复制了HTTP标头。这是代码: 但是,这是我收到的回复: 我知道我可以使用来做到这一点,但是当我手动发送HTTP请求时,服务器为什么不识别HTTP请求? 问题答案: 两件事情: 您应该使用而不是将条目打印到单独的行。 HTTP请求应以空白行(link)结尾。所以加

  • 问题内容: 我正在学习Java套接字。我正在尝试向Facebook发送HTTPS GET请求,如下所示: 然后,我尝试侦听来自服务器的传入数据,如下所示: 但是我没有从服务器获得任何返回数据。为什么? 问题答案: 两个答案。 您正在尝试与HTTPS服务器通信。这要求您建立一个SSL / TLS通道。这在纯套接字上确实很难>>您必须实现连接协商,密钥链的客户端验证,会话加密/解密等。 一个更合理的方

  • 我是一个初学者程序员,所以这很可能是显而易见的,我忽略了答案。但说到这个问题。 我有一个由两部分组成的程序(它比这个例子稍微复杂一点,但情况是一样的)。该程序在客户端和服务器之间触发了多条消息。我在服务器端有一个PrintWriter来向客户机发送消息,在客户机上有一个BufferedReader来读取发送的消息。当这个例子运行时,我得到了两行作为输出。第一个消息是两个消息,第二个消息是NULL。

  • 问题内容: 我创建了一个服务器应用程序,该应用程序从客户端接收声音,然后广播此声音,该声音以字节存储,然后将字节发送回连接到服务器的客户端。现在,我目前仅使用一个客户端进行测试,客户端正在接收语音,但是声音一直在卡顿。有人可以告诉我我做错了吗? 我想我理解为什么声音播放不流畅但不了解如何解决问题的部分原因。 代码是波纹管的。 客户端: 将声音发送到服务器的部分 从服务器接收数据字节的部分 问题答案