如何从 Java 中的 HttpServletRequest 检索原始帖子数据
Posted
技术标签:
【中文标题】如何从 Java 中的 HttpServletRequest 检索原始帖子数据【英文标题】:How to retrieve raw post data from HttpServletRequest in java 【发布时间】: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() 方法 - 没有人认为这会有用吗?
那么我怎样才能编写这个方法,让它总是返回正确的帖子数据呢?
【问题讨论】:
【参考方案1】:HttpServletRequest#getInputStream()
可以以字节流的形式获取请求正文:
InputStream body = request.getInputStream();
// ...
或作为HttpServletRequest#getReader()
的字符流:
Reader body = request.getReader();
// ...
请注意,您只能阅读一次。客户端不会多次重新发送相同的请求。调用getParameter()
等也会隐式读取它。如果您以后需要分解参数,则必须将主体存储在某个地方并自己处理。
【讨论】:
所以你的回答是没有没有的方法来做我想做的事?它不是关于客户多次发送它。 HttpServletRequest 清楚地将发布数据存储在内部某处(因为您总是可以多次获取发布参数)。感谢您的回答,我只是想完全理解您是在说“不可能”,还是只是在重申我已经发现的内容。 在第一次调用getParameter()
时,HttpServletRequest
将在内部使用getInputStream()
来读取和解析请求正文(它是来自网络连接的字节流)并将其存储在您可以使用的映射中可以通过getParameterMap()
获得。在此之后,您将无法再读取getInputStream()
/getReader()
的请求正文,因为它已经被读取了。如果您更清楚地阐明此需求背后的功能需求,那么我们或许可以向您建议更好的方法来实现它。
好吧,您可能想要创建一个HttpServletRequestWrapper
,它在ByteArrayInputStream
中保存请求正文的副本。
这是您正在寻找的请求包装器的示例:***.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"
其余值(邮件、姓氏、姓名)设置为空
【讨论】:
我认为这个答案与提出的问题无关以上是关于如何从 Java 中的 HttpServletRequest 检索原始帖子数据的主要内容,如果未能解决你的问题,请参考以下文章