来自 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 请求。
- 客户端<=>飞行前(OPTIONS)请求<=>服务器
- 客户端<=> 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>
我有两个应用程序:一个 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 请求。
- 客户端<=>飞行前(OPTIONS)请求<=>服务器
- 客户端<=> 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>