来自 javascript 应用程序的 POST 请求正文在到达服务器时在浏览器中使用 XMLHttpRequest 为空

Body of POST request from javascript application in browser using XMLHttpRequest is empty when arriving at the server

我有两个应用程序:一个 Web 客户端和一个 java 服务器。 Web 客户端发送带有 JSON 数据主体的 HTTP POST 请求,服务器应接收数据并将其显示在屏幕上。问题是,当服务器读取请求的主体时,没有任何内容可读。怎么了?

编辑:我意识到问题出在浏览器端(因为我可以从其他网站发送和读取 HTTP POST 请求),但我仍然不知道问题出在哪里。这与浏览器运行宁代码有关吗?当我使用 Chrome 时,我遇到了所描述的问题。当我使用 Firefox 或 IE 时,甚至没有通知 java 服务器;它甚至没有 运行 在收到 HTTP 请求时应该 运行 的处理方法。

当我将内容类型编码为 url 编码时,它可以在服务器上读取数据。我认为它是:x-www-form-urlencoded。但我想将数据发送为 JSON.

Web 客户端我使用 XMLHttpRequest,如您所见below.TheWeb 客户端:

<!DOCTYPE html>
    <html>
    <body>
        <script>
        
        function handleInput(){
            var title = "title";
            var reviewer = "reviewer";
            
            const xhr = new XMLHttpRequest();
            
            var searchInfo = {
                title:title,
                reviewer:reviewer
            };

            xhr.open('POST', 'http://localhost:8001');
            xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
            xhr.send(JSON.stringify(searchInfo));
            
        }
      
        </script>
    
    </body>
    </html

服务器:

import java.io.IOException;
import java.net.InetSocketAddress;

import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class Server {

    public static void main(String[] args) {
        try {
            HttpServer server = HttpServer.create(new InetSocketAddress("localhost", 8001), 0);
            HttpHandler handler = new MyHttpHandler();
            HttpContext context = server.createContext("/");
            context.setHandler(handler);
            server.start();
            System.out.println("Server started on port 8001");
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }

}

服务器 HTTP 处理程序:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;

public class MyHttpHandler implements HttpHandler {

    @Override
    public void handle(HttpExchange httpExchange) throws IOException {
        InputStream is = httpExchange.getRequestBody();

        BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
        StringBuilder content = new StringBuilder();
        String line;

        while ((line = br.readLine()) != null) { br.readLine is always null!!!
            content.append(line);
            content.append("\n");
        }

        System.out.println("Content: " + content.toString());

    }
}

因为您的服务器(java 端,住在 localhost:8001)和客户端(xhttp 端,住在其他地方)是分开的。该请求被视为跨源请求 (COR)。

有两种类型的跨源请求 - 安全和不安全:

  • 只有以下 Content-Type 在跨站请求中被认为是安全的:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

因此,application/json; 被认为是不安全的。


为了安全请求,对服务器没有太多限制,所以你可以在使用时得到响应 application/x-www-form-urlencoded

  • 客户端<=> POST请求<=>服务器

对于不安全的请求,有一个预检请求(一个特殊的OPTIONS动作)来询问服务器

  • 如果允许客户端来源并且
  • 客户能做什么

在提出真正的请求之前,在您的情况下是 POST 请求。

  1. 客户端<=>飞行前(OPTIONS)请求<=>服务器
  2. 客户端<=> POST请求<=>服务器

所以问题是没有处理预检请求,服务器无法处理该请求。 要处理它,您需要按如下方式更改您的处理程序:

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;

public class MyHttpHandler implements HttpHandler {

    @Override
    public void handle(HttpExchange httpExchange) throws IOException {
        Headers headers = httpExchange.getResponseHeaders();
        System.out.println(httpExchange.getRequestMethod());
        headers.add("Access-Control-Allow-Origin", "*"); // * means allow all origin, in production, it should be the origin you trust e.g. http://client.abc.com

        if (httpExchange.getRequestMethod().equalsIgnoreCase("OPTIONS")) {
            headers.add("Access-Control-Allow-Headers", "Content-Type"); // allow clients to pass in content-type
            headers.add("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
            httpExchange.sendResponseHeaders(204, -1);
            return;
        }

        InputStream is = httpExchange.getRequestBody();
        BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
        StringBuilder content = new StringBuilder();
        String line;

        while ((line = br.readLine()) != null) { // br.readLine is always null!!!
                content.append(line);
            content.append("\n");
        }

        System.out.println("Content: " + content.toString());

        // added response as well to complete the request
        String response = "Good" ;
        httpExchange.sendResponseHeaders(200, response.length());
        OutputStream os = httpExchange.getResponseBody();
        os.write(response.getBytes(StandardCharsets.UTF_8));
        os.close();
        httpExchange.close();
    }
}

HTML

<!DOCTYPE html>
<html>
  <body>
    <button onclick="handleInput()">Click</button>
    <script>
      function handleInput() {
        var title = "title";
        var reviewer = "reviewer";

        const xhr = new XMLHttpRequest();
        xhr.onload = function() {
            console.log('done')
        }

        var searchInfo = {
          title: title,
          reviewer: reviewer,
        };

        xhr.open("POST", "http://localhost:8001");
        xhr.setRequestHeader("Content-Type", "application/json; charset=UTF-8");
        xhr.send(JSON.stringify(searchInfo));
      }
    </script>
  </body>
</html>

进一步了解 COR:

https://javascript.info/fetch-crossorigin


为了你的html

<form name="searchForm" id="searchForm" onSubmit="handleInput(event)">
...
</form>


<script>
function handleInput(e){
   e.preventDefault()
   ...
}
</script>