从Spring异常处理程序中读取httprequest内容
我正在使用Spring的@ExceptionHandler
注释来捕获控制器中的异常。
有些请求将POST数据保存为写入请求正文的纯XML字符串,我想读取该数据以记录异常。问题是当我在异常处理程序中请求inputstream并尝试从中读取时,该流返回-1(空)。
异常处理程序签名为:
@ExceptionHandler(Throwable.class)public ModelAndView exception(HttpServletRequest request, HttpServletResponse response, HttpSession session, Throwable arff)
有什么想法吗?有没有办法访问请求正文?
我的控制器:
@Controller@RequestMapping("/user/**")
public class UserController {
static final Logger LOG = LoggerFactory.getLogger(UserController.class);
@Autowired
IUserService userService;
@RequestMapping("/user")
public ModelAndView getCurrent() {
return new ModelAndView("user","response", userService.getCurrent());
}
@RequestMapping("/user/firstLogin")
public ModelAndView firstLogin(HttpSession session) {
userService.logUser(session.getId());
userService.setOriginalAuthority();
return new ModelAndView("user","response", userService.getCurrent());
}
@RequestMapping("/user/login/failure")
public ModelAndView loginFailed() {
LOG.debug("loginFailed()");
Status status = new Status(-1,"Bad login");
return new ModelAndView("/user/login/failure", "response",status);
}
@RequestMapping("/user/login/unauthorized")
public ModelAndView unauthorized() {
LOG.debug("unauthorized()");
Status status = new Status(-1,"Unauthorized.Please login first.");
return new ModelAndView("/user/login/unauthorized","response",status);
}
@RequestMapping("/user/logout/success")
public ModelAndView logoutSuccess() {
LOG.debug("logout()");
Status status = new Status(0,"Successful logout");
return new ModelAndView("/user/logout/success", "response",status);
}
@RequestMapping(value = "/user/{id}", method = RequestMethod.POST)
public ModelAndView create(@RequestBody UserDTO userDTO, @PathVariable("id") Long id) {
return new ModelAndView("user", "response", userService.create(userDTO, id));
}
@RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
public ModelAndView getUserById(@PathVariable("id") Long id) {
return new ModelAndView("user", "response", userService.getUserById(id));
}
@RequestMapping(value = "/user/update/{id}", method = RequestMethod.POST)
public ModelAndView update(@RequestBody UserDTO userDTO, @PathVariable("id") Long id) {
return new ModelAndView("user", "response", userService.update(userDTO, id));
}
@RequestMapping(value = "/user/all", method = RequestMethod.GET)
public ModelAndView list() {
return new ModelAndView("user", "response", userService.list());
}
@RequestMapping(value = "/user/allowedAccounts", method = RequestMethod.GET)
public ModelAndView getAllowedAccounts() {
return new ModelAndView("user", "response", userService.getAllowedAccounts());
}
@RequestMapping(value = "/user/changeAccount/{accountId}", method = RequestMethod.GET)
public ModelAndView changeAccount(@PathVariable("accountId") Long accountId) {
Status st = userService.changeAccount(accountId);
if (st.code != -1) {
return getCurrent();
}
else {
return new ModelAndView("user", "response", st);
}
}
/*
@RequestMapping(value = "/user/logout", method = RequestMethod.GET)
public void perLogout(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
userService.setOriginalAuthority();
response.sendRedirect("/marketplace/user/logout/spring");
}
*/
@ExceptionHandler(Throwable.class)
public ModelAndView exception(HttpServletRequest request, HttpServletResponse response, HttpSession session, Throwable arff) {
Status st = new Status();
try {
Writer writer = new StringWriter();
byte[] buffer = new byte[1024];
//Reader reader2 = new BufferedReader(new InputStreamReader(request.getInputStream()));
InputStream reader = request.getInputStream();
int n;
while ((n = reader.read(buffer)) != -1) {
writer.toString();
}
String retval = writer.toString();
retval = "";
} catch (IOException e) {
e.printStackTrace();
}
return new ModelAndView("profile", "response", st);
}
}
谢谢
回答:
当您从中读取内容时,我已经尝试过您的代码,并且在异常处理程序中发现了一些错误InputStream
:
Writer writer = new StringWriter();byte[] buffer = new byte[1024];
//Reader reader2 = new BufferedReader(new InputStreamReader(request.getInputStream()));
InputStream reader = request.getInputStream();
int n;
while ((n = reader.read(buffer)) != -1) {
writer.toString();
}
String retval = writer.toString();
retval = "";
我已经用以下代码替换了您的代码:
BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));String line = "";
StringBuilder stringBuilder = new StringBuilder();
while ( (line=reader.readLine()) != null ) {
stringBuilder.append(line).append("\n");
}
String retval = stringBuilder.toString();
然后,我可以从InputStream
异常处理程序中读取内容,它可以正常工作!如果仍然无法读取InputStream
,建议您检查如何将xml数据发布到请求正文。您应该考虑Inputstream
每个请求只能使用一次,因此建议您检查是否没有其他对的调用getInputStream()
。如果必须调用它两次或更多次,则应编写一个HttpServletRequestWrapper
这样的自定义内容来制作请求正文的副本,以便可以多次阅读。
您的评论已帮助我重现此问题。您使用了@RequestBody注释,因此您没有调用getInputStream()
,但是Spring会调用它来检索请求的正文。看一看该类org.springframework.web.bind.annotation.support.HandlerMethodInvoker
:如果使用@RequestBody
此类调用resolveRequestBody
方法,依此类推…最终您将无法再InputStream
从中读取ServletRequest
。如果仍然要同时使用@RequestBody
和getInputStream()
自己的方法,则必须将请求包装到自定义文件中HttpServletRequestWrapper
以制作请求正文的副本,以便可以手动读取多次。这是我的包装:
public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper { private static final Logger logger = Logger.getLogger(CustomHttpServletRequestWrapper.class);
private final String body;
public CustomHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line = "";
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
logger.error("Error reading the request body...");
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
logger.error("Error closing bufferedReader...");
}
}
}
body = stringBuilder.toString();
}
@Override
public ServletInputStream getInputStream() throws IOException {
final StringReader reader = new StringReader(body);
ServletInputStream inputStream = new ServletInputStream() {
public int read() throws IOException {
return reader.read();
}
};
return inputStream;
}
}
然后,您应该编写一个简单Filter
的包装请求:
public class MyFilter implements Filter { public void init(FilterConfig fc) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(new CustomHttpServletRequestWrapper((HttpServletRequest)request), response);
}
public void destroy() {
}
}
最后,您必须在web.xml中配置过滤器:
<filter> <filter-name>MyFilter</filter-name>
<filter-class>test.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
您可以仅针对确实需要过滤器的控制器触发过滤器,因此应根据需要更改url-pattern。
如果仅在一个控制器中需要此功能,当您通过@RequestBody
注释收到请求主体时,也可以在该控制器中复制该请求主体。
以上是 从Spring异常处理程序中读取httprequest内容 的全部内容, 来源链接: utcz.com/qa/400957.html