ChatGPT解决这个技术问题 Extra ChatGPT

从 Java servlet 中的 POST 请求获取请求有效负载

我有一个向我的 Java servlet 发送 POST 请求的 javascript 库,但在 doPost 方法中,我似乎无法获取请求负载的内容。在 chrome 开发者工具中,所有内容都在 headers 选项卡的 Request Payload 部分中,并且内容在那里,我知道 doPost 方法正在接收 POST,但它只是空白。

对于 HttpServletRequest 对象,我可以通过什么方式获取请求负载中的数据?

执行 request.getParameter()request.getAttributes() 最终都没有数据

您需要指定哪个参数,例如,如果您在正文中有关键字,请使用 String keyword = request.getParameter("keyword");
看到发送请求的 JavaScript 代码会很有趣。它显然是以错误的方式组成请求参数。
@Razh 是的,我知道,我只是在指定我正在尝试的方法。 BalusC 我正在使用 resumable.js 库来处理拆分文件上传
如果我没记错的话,在从输入流中读取之前不要使用 request.getParameter() 是很重要的,否则将没有可用的数据(已经读取)。

d
davidfrancis

简单回答:使用 getReader() 读取请求正文

更多信息:有两种方法可以读取正文中的数据:

getReader() 返回一个 BufferedReader,它允许您读取请求的正文。如果您需要读取二进制数据,getInputStream() 将返回一个 ServletInputStream。

文档中的注释:“可能会调用 [任一方法] 来读取正文,而不是同时调用两者。”


没问题,就是有点隐蔽
如果您刚刚在过滤器中使用了它,然后发现没有其他东西可以再次读取正文,那么这篇文章可能会很有用! natch3z.blogspot.co.uk/2009/01/read-request-body-in-filter.html
@SgtPooki 随时为该评论添加一些推理,我的好先生!
@davidfrancis我不想在这里对您进行个人评判,但是:您没有提供任何上下文..没有文档链接,没有示例。您对我的评论的回复似乎比答案本身需要更多的努力。
@SgtPooki 正确,因为不需要这些东西。恕我直言,所需方法的名称有些晦涩,因此方法名称就是这个问题的答案。和我想的一样简单。如果您认为有用,请随时提交更长的答案。
O
OneCricketeer
String payloadRequest = getBody(request);

使用这种方法

public static String getBody(HttpServletRequest request) throws IOException {

    String body = null;
    StringBuilder stringBuilder = new StringBuilder();
    BufferedReader bufferedReader = null;

    try {
        InputStream inputStream = request.getInputStream();
        if (inputStream != null) {
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            char[] charBuffer = new char[128];
            int bytesRead = -1;
            while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                stringBuilder.append(charBuffer, 0, bytesRead);
            }
        } else {
            stringBuilder.append("");
        }
    } catch (IOException ex) {
        throw ex;
    } finally {
        if (bufferedReader != null) {
            try {
                bufferedReader.close();
            } catch (IOException ex) {
                throw ex;
            }
        }
    }

    body = stringBuilder.toString();
    return body;
}

考虑到 request.getInputStream() 不像 request.getReader() 那样接受请求字符编码。所以这个例子使用默认的系统字符集。
new BufferedReader(new InputStreamReader(request.getInputStream())) 可以简化为已缓冲的 request.getReader() 并且还保留请求编码。
我发现这个解决方案很有帮助,因为引发了异常:javax.servlet.ServletException: java.lang.IllegalStateException: getInputStream() has already been called for this request 当我调用 getReader() 因为阅读器已经打开时。
谢谢先生,这是一个干净简洁的解决方案!
为什么将空字符串附加到 SB?
s
scriptfoo

您可以从请求中使用 Buffer Reader 来读取

    // Read from request
    StringBuilder buffer = new StringBuilder();
    BufferedReader reader = request.getReader();
    String line;
    while ((line = reader.readLine()) != null) {
        buffer.append(line);
        buffer.append(System.lineSeparator());
    }
    String data = buffer.toString()

b
bbviana

Java 8 流

String body = request.getReader().lines()
    .reduce("", (accumulator, actual) -> accumulator + actual);

这很有趣,但在字符串连接方面看起来效率很低!有什么办法可以改进吗?
String body = request.getReader().lines().collect(Collectors.joining());也可以工作。 Collectors.joining 显然在后台使用了 StringBuilder。
我认为它应该 request.getReader().lines().collect(joining("\n")) 保留换行符。
在 java 8 中,stream 将被并行处理,因此需要添加顺序方法,否则它将合并错误的数据部分 - String body = request.getReader().lines().sequential().reduce(System.lineSeparator(), (累加器,实际)-> 累加器 + 实际)
您可以将 (accumulator, actual) -> accumulator + actual 替换为 String::concat
D
Diji Adeyemo

使用 Apache Commons IO,您可以在一行中完成此操作。

IOUtils.toString(request.getReader())

t
twonkeys

如果正文的内容是 Java 8 中的字符串,您可以执行以下操作:

String body = request.getReader().lines().collect(Collectors.joining());


H
Harry Developer

如果您能够以 JSON 格式发送有效负载,这是读取播放负载的最方便的方法:

示例数据类:

public class Person {
    String firstName;
    String lastName;
    // Getters and setters ...
}

示例有效负载(请求正文):

{ "firstName" : "John", "lastName" : "Doe" }

在 servlet 中读取有效负载的代码(需要 com.google.gson.*):

Person person = new Gson().fromJson(request.getReader(), Person.class);

就这样。漂亮,简单,干净。不要忘记将 content-type 标头设置为 application/json。


这适用于我必须实现 JWT 身份验证的情况。我正在发送带有用户名和密码的 JSON 有效负载,然后将其映射到我的自定义 Auth Token 类。
T
Timothy Heider

使用 Java 8 尝试资源:

    StringBuilder stringBuilder = new StringBuilder();
    try(BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(request.getInputStream()))) {
        char[] charBuffer = new char[1024];
        int bytesRead;
        while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
            stringBuilder.append(charBuffer, 0, bytesRead);
        }
    }

K
Komal12

你只需要

request.getParameterMap()

用于获取 POST 和 GET - 参数。

该方法返回一个 Map<String,String[]>

您可以通过以下方式读取地图中的参数

Map<String, String[]> map = request.getParameterMap();
//Reading the Map
//Works for GET && POST Method
for(String paramName:map.keySet()) {
    String[] paramValues = map.get(paramName);

    //Get Values of Param Name
    for(String valueOfParam:paramValues) {
        //Output the Values
        System.out.println("Value of Param with Name "+paramName+": "+valueOfParam);
    }
}

注意:这些参数仅在您使用编码 application/x-www-form-urlencoded 时可用;对于 multipart/form-data,您显然需要通过 request.getReader() 访问正文部分并手动解析它。