【问题标题】:How to retrieve raw post data from HttpServletRequest in java如何从 Java 中的 HttpServletRequest 检索原始帖子数据
【发布时间】:2011-06-28 18:22:50
【问题描述】:

我正在尝试用 Java 获取发布数据。似乎它应该是最简单的事情之一,对吗?我的意思是, HttpServletRequest.getParameter 必须做对吗?那么如何获取原始帖子数据呢?

我找到HttpServletRequest get JSON POST data 并使用Kdeveloper 的代码从请求中提取帖子数据。它有效,但有一个问题:我只能获得该帖子数据一次

这是我用 Kdeveloper 的代码制作的方法:

public static String getPostData(HttpServletRequest req) {
    StringBuilder sb = new StringBuilder();
    try {
        BufferedReader reader = req.getReader();
        reader.mark(10000);

        String line;
        do {
            line = reader.readLine();
            sb.append(line).append("\n");
        } while (line != null);
        reader.reset();
        // do NOT close the reader here, or you won't be able to get the post data twice
    } catch(IOException e) {
        logger.warn("getPostData couldn't.. get the post data", e);  // This has happened if the request's reader is closed    
    }

    return sb.toString();
}

以前我在这个方法结束时关闭了阅读器,但是当方法在同一个请求上运行多次时会导致异常。不关闭它,不会发生异常,但该方法返回一个空字符串。

老实说,应该只公开一个 req.getPostData() 方法 - 没有人认为这会有用吗?

那么我怎样才能编写这个方法,让它总是返回正确的帖子数据呢?

【问题讨论】:

    标签: java http servlets post


    【解决方案1】:

    HttpServletRequest#getInputStream() 可以以字节流的形式获取请求正文:

    InputStream body = request.getInputStream();
    // ...
    

    作为HttpServletRequest#getReader()的字符流:

    Reader body = request.getReader();
    // ...
    

    请注意,您只能阅读一次。客户端不会多次重新发送相同的请求。调用getParameter() 等也会隐式读取它。如果您以后需要分解参数,则必须将主体存储在某个地方并自己处理。

    【讨论】:

    • 所以你的回答是没有没有的方法来做我想做的事?它不是关于客户多次发送它。 HttpServletRequest 清楚地将发布数据存储在内部某处(因为您总是可以多次获取发布参数)。感谢您的回答,我只是想完全理解您是在说“不可能”,还是只是在重申我已经发现的内容。
    • 在第一次调用getParameter() 时,HttpServletRequest 将在内部使用getInputStream() 来读取和解析请求正文(它是来自网络连接的字节流)并将其存储在您可以使用的映射中可以通过getParameterMap()获得。在此之后,您将无法再读取getInputStream()/getReader() 的请求正文,因为它已经被读取了。如果您更清楚地阐明此需求背后的功能需求,那么我们或许可以向您建议更好的方法来实现它。
    • 好吧,您可能想要创建一个HttpServletRequestWrapper,它在ByteArrayInputStream 中保存请求正文的副本。
    • 这是您正在寻找的请求包装器的示例:stackoverflow.com/questions/1046721/…
    • 感谢您的回答。 “只读一次”...不得不说我对这个设计决定感到非常惊讶。
    【解决方案2】:

    我们遇到过 IE 强制我们以 text/plain 形式发布的情况,因此我们不得不使用 getReader 手动解析参数。 servlet 被用于长轮询,因此当 AsyncContext::dispatch 在延迟后执行时,它实际上是空手重新发布请求。

    所以我只是在请求第一次出现时使用 HttpServletRequest::setAttribute 将帖子存储在请求中。 getReader 方法清空缓冲区,其中 getParameter 也清空缓冲区,但自动存储参数。

        String input = null;
    
        // we have to store the string, which can only be read one time, because when the
        // servlet awakens an AsyncContext, it reposts the request and returns here empty handed
        if ((input = (String) request.getAttribute("com.xp.input")) == null) {
            StringBuilder buffer = new StringBuilder();
            BufferedReader reader = request.getReader();
    
            String line;
            while((line = reader.readLine()) != null){
                buffer.append(line);
            }
            // reqBytes = buffer.toString().getBytes();
    
            input = buffer.toString();
            request.setAttribute("com.xp.input", input);
        }
    
        if (input == null) {
            response.setContentType("text/plain");
            PrintWriter out = response.getWriter();
            out.print("{\"act\":\"fail\",\"msg\":\"invalid\"}");
        }       
    

    【讨论】:

      【解决方案3】:

      这对我有用:(注意需要 java 8)

      String requestData = request.getReader().lines().collect(Collectors.joining());
      UserJsonParser u = gson.fromJson(requestData, UserJsonParser.class);
      

      UserJsonParse 是一个展示 gson 如何解析 json 共振峰的类。

      类是这样的:

      public class UserJsonParser {
      
          private String username;
          private String name;
          private String lastname;
          private String mail;
          private String pass1;
      //then put setters and getters
      }
      

      解析出来的json字符串是这样的:

      $jsonData: {    "username": "testuser",    "pass1": "clave1234" }
      

      其余值(邮件、姓氏、姓名)设置为空

      【讨论】:

      • 我认为这个答案与提出的问题无关
      猜你喜欢
      • 2018-05-16
      • 2016-08-29
      • 1970-01-01
      • 1970-01-01
      • 2023-02-07
      • 2021-07-06
      • 2010-12-19
      • 2010-11-24
      相关资源
      最近更新 更多