从 spring 异常处理程序读取 httprequest 内容

2023-12-22

我正在使用 Spring 的@ExceptionHandler注释来捕获我的控制器中的异常。

有些请求将 POST 数据作为写入请求正文的纯 XML 字符串,我想读取该数据以记录异常。 问题是,当我在异常处理程序中请求输入流并尝试从中读取时,流返回-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 数据 POST 到请求正文。 您应该考虑到您可以食用Inputstream每个请求只能调用一次,因此我建议您检查是否有其他调用getInputStream()。如果你必须调用它两次或更多次,你应该编写一个自定义的HttpServletRequestWrapper像这样复制请求正文,以便您可以多次阅读。

UPDATE
您的评论帮助我重现了该问题。你使用了注解@RequestBody,所以确实没有调用getInputStream(),但 Spring 调用它来检索请求的正文。看看班级org.springframework.web.bind.annotation.support.HandlerMethodInvoker: 如果你使用@RequestBody这个类调用resolveRequestBody方法等等……最后你就看不下去了InputStream从你的ServletRequest。如果您仍想同时使用两者@RequestBody and 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注解。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从 spring 异常处理程序读取 httprequest 内容 的相关文章

随机推荐

  • 自定义 HTML 插件创建 index.html 不影响

    我已经创建了这样的自定义 xhtml 插件 我的plugin xml代码是
  • 关于布局别名的 Android 文档不正确?

    我想弄清楚如何使用最少的样板代码重用或 别名 布局 看来关于布局别名的 Android 文档 http developer android com training multiscreen screensizes html TaskUseA
  • 带有 React useEffect 钩子的 componentWillUnmount

    怎样才能useEffect钩子 或任何其他与此相关的钩子 用于复制componentWillUnmount 在传统的类组件中我会做这样的事情 class Effect extends React PureComponent componen
  • StartPosition 设置为 CenterPosition 但我的表单未居中

    我正在使用 Visual Studio 2012 我的表单打开时不会以屏幕为中心 我有表格StartPosition set to CenterScreen 但它总是从我的左显示器的左上角开始 我有 2 个显示器 有任何想法吗 谢谢 试试这
  • 删除长度为 1 的 Julia 数组维度

    假设我有一个大小为 1024x1024x1x1x100 的 5D 数组 如何制作一个 1024x1024x100 的新数组 如果您提前知道要保留哪些维度 则以下操作有效 arr arr 1 1 But 我提前不知道哪些尺寸是多少我只想保留给
  • Databricks 笔记本挂着 pytorch

    我们遇到 Databricks 笔记本问题 我们的一个笔记本单元似乎挂起 而驱动程序日志确实显示该笔记本单元已被执行 有谁知道为什么我们的笔记本单元一直挂起并且无法完成 请参阅下面的详细信息 情况 我们正在训练 ML 模型pytorch在
  • 如何使用 Photoshop JavaScript 将文本写入文本文件?

    我看了一下Photoshop CS5 脚本编写指南和 Photoshop CS5 JavaScript 参考 http www adobe com devnet photoshop scripting html 但我找不到将文本写入纯文本文
  • 如何使用 TensorFlow 实现 k-means?

    介绍教程使用内置的梯度下降优化器 非常有意义 然而 k 均值不仅仅是我可以插入梯度下降中的东西 看起来我必须编写自己的优化器 但考虑到 TensorFlow 原语 我不太确定如何做到这一点 我应该采取什么方法 注 您现在可以获得这段代码的更
  • 如何用 C++ 确定 Linux 系统 RAM 的大小?

    我刚刚编写了以下 C 函数来以编程方式确定系统安装了多少 RAM 它有效 但在我看来应该有一种更简单的方法来做到这一点 我错过了什么吗 getRAM FILE stream popen head n1 proc meminfo r std
  • 何时设置 JVM 字节码访问修饰符标志 0x1000(十六进制)“合成”?

    对于某些 Java 字节码解析器项目 我阅读了 JVM 规范 发现 Java 虚拟机类文件格式访问修饰符字段的位掩码值是 ACC PUBLIC 0x0001 ACC FINAL 0x0010 ACC SUPER 0x0020 old inv
  • 错误 无效的挂钩调用。钩子只能在函数组件体内调用

    我正在做一个 React Electron 应用程序 但收到此错误 错误 无效的挂钩调用 钩子只能在函数组件的主体内部调用 发生这种情况可能是由于以下原因之一 1 您的React和渲染器版本可能不匹配 例如React DOM 2 你可能违反
  • 获取控件组件内的控件属性

    我创建了一个自定义输入组件 但我想处理组件内部的错误 因此 为了进行验证 我需要从控制对象中获取错误 是否可以 我的组件完全一样here http almerosteyn com 2016 04 linkup custom control
  • 我在输出末尾得到了 { } 。造成这种情况的原因是什么以及如何消除它?

    我正在尝试一个简单的图形用户界面 它可以在同一窗口中使用 秘密号码 密钥标识符来加密和解密消息 以获取乐趣 到目前为止 它有效 我对此非常满意 我唯一的问题是我在 crypt 函数中得到了我想要的输出返回值 后跟 使用普通的 print 函
  • 如何让 Require.js 获取不以“.js”结尾的脚本? [复制]

    这个问题在这里已经有答案了 我正在开发一个应用程序 它使用某个网站来使付款更容易 并且它处理付款的方式需要从此网址导入一些javascripthttps bridge paymill com 包含脚本 事实是 我正在使用 require j
  • 数组连接与字符串连接

    哪种方法更快 数组连接 var str to split a b c d e f g h i j k l m n o p q r s t u v w x y z var myarray str to split split var outp
  • 带有使用 NIB 的委托的 UIView 子类

    我正在尝试使用笔尖对 UIView 进行子类化 使用以下代码 void awakeFromNib super awakeFromNib NSArray v NSBundle mainBundle loadNibNamed Qus Scale
  • 模板文字适用于除 IE 之外的其他浏览器

    我正在研究 javascript 并使用 模板文字 它适用于 Chrome 和 Firefox 但不适用于 Internet Explorer IE var a 10 console log a 模板文字是ES6 IE支持very fewE
  • 如何从服务器端清除浏览器缓存?

    我必须创建一个处理用户敏感信息的网络应用程序 我需要在用户注销后立即清除浏览器的缓存 因为缓存的数据容易受到攻击 应强制客户端浏览器清除服务器端的缓存 此外 所有缓存策略都必须从服务器端公开给客户端 这个问题有什么解决办法吗 将响应设置为立
  • std::thread 调用类的方法[重复]

    这个问题在这里已经有答案了 可能的重复 使用成员函数启动线程 https stackoverflow com questions 10673585 start thread with member function 我有一个小班 class
  • 从 spring 异常处理程序读取 httprequest 内容

    我正在使用 Spring 的 ExceptionHandler注释来捕获我的控制器中的异常 有些请求将 POST 数据作为写入请求正文的纯 XML 字符串 我想读取该数据以记录异常 问题是 当我在异常处理程序中请求输入流并尝试从中读取时 流