来源:自学PHP网 时间:2020-09-27 14:34 作者:小飞侠 阅读:次
[导读] SpringBoot拦截器如何获取http请求参数...
今天带来SpringBoot拦截器如何获取http请求参数教程详解 1.1、获取http请求参数是一种刚需 我想有的小伙伴肯定有过获取http请求的需要,比如想
等等各式各样的场景,这时你就需要获取 HTTP 请求的参数或者请求body,一般思路有两种,一种就是自定义个AOP去拦截目标方法,第二种就是使用拦截器。整体比较来说,使用拦截器更灵活些,因为每个接口的请求参数定义不同,使用AOP很难细粒度的获取到变量参数,本文主线是采用拦截器来获取HTTP请求。 1.2、定义拦截器获取请求 基于 spring-boot-starter-parent 2.1.9.RELEASE 看起来这个很简单,这里就直接上code,定义个拦截器 /** * @author axin * @summary HTTP请求拦截器 */ @Slf4j public class RequestInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //获取请求参数 String queryString = request.getQueryString(); log.info("请求参数:{}", queryString); //获取请求body byte[] bodyBytes = StreamUtils.copyToByteArray(request.getInputStream()); String body = new String(bodyBytes, request.getCharacterEncoding()); log.info("请求体:{}", body); return true; } } 然后把这个拦截器配置一下中: /** * WebMVC配置,你可以集中在这里配置拦截器、过滤器、静态资源缓存等 */ @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new RequestInterceptor()).addPathPatterns("/**"); } } 定义个接口测试一下 /** * @author axin * @summary 提交测试接口 */ @Slf4j @RestController public class MyHTTPController { @GetMapping("/v1/get") public void get(@RequestParam("one") String one, @RequestParam("two") BigDecimal number) { log.info("参数:{},{}", one, number); } @PostMapping("/v1/post") public void check(@RequestBody User user) { log.info("{}", JSON.toJSONString(user)); } } GET请求获取请求参数示例: POST请求获取请求Body示例: 我们发现拦截器在获取HTTP请求的body时出现了 400 (Required request body is missing: public void com.axin.world.controller.MyHTTPController.check(com.axin.world.domain.User));同时也发现拦截器竟然走了两遍,这又是咋回事呢? 1.3、为什么拦截器会重复调两遍呢? 其实是因为 tomcat截取到异常后就转发到/error页面,就在这个转发的过程中导致了springmvc重新开始DispatcherServlet的整个流程,所以拦截器执行了两次,我们可以看下第二次调用时的url路径: 1.4、ServletInputStream(CoyoteInputStream) 输入流无法重复调用 而之前出现的 Required request body is missing 错误 其实是ServletInputStream被读取后无法第二次再读取了,所以我们要把读取过的内容存下来,然后需要的时候对外提供可被重复读取的ByteArrayInputStream。 对于MVC的过滤器来说,我们就需要重写 ServletInputStream 的 getInputStream()方法。 1.5、自定义 HttpServletRequestWrapper 为了 重写 ServletInputStream 的 getInputStream()方法,我们需要自定义一个 HttpServletRequestWrapper : /** * @author Axin * @summary 自定义 HttpServletRequestWrapper 来包装输入流 */ public class AxinHttpServletRequestWrapper extends HttpServletRequestWrapper { /** * 缓存下来的HTTP body */ private byte[] body; public AxinHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); body = StreamUtils.copyToByteArray(request.getInputStream()); } /** * 重新包装输入流 * @return * @throws IOException */ @Override public ServletInputStream getInputStream() throws IOException { InputStream bodyStream = new ByteArrayInputStream(body); return new ServletInputStream() { @Override public int read() throws IOException { return bodyStream.read(); } /** * 下面的方法一般情况下不会被使用,如果你引入了一些需要使用ServletInputStream的外部组件,可以重点关注一下。 * @return */ @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return true; } @Override public void setReadListener(ReadListener readListener) { } }; } @Override public BufferedReader getReader() throws IOException { InputStream bodyStream = new ByteArrayInputStream(body); return new BufferedReader(new InputStreamReader(getInputStream())); } } 然后定义一个 DispatcherServlet子类来分派 上面自定义的 AxinHttpServletRequestWrapper : /** * @author Axin * @summary 自定义 DispatcherServlet 来分派 AxinHttpServletRequestWrapper */ public class AxinDispatcherServlet extends DispatcherServlet { /** * 包装成我们自定义的request * @param request * @param response * @throws Exception */ @Override protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { super.doDispatch(new AxinHttpServletRequestWrapper(request), response); } } 然后配置一下: /** * WebMVC配置,你可以集中在这里配置拦截器、过滤器、静态资源缓存等 */ @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new RequestInterceptor()).addPathPatterns("/**"); } @Bean @Qualifier(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) public DispatcherServlet dispatcherServlet() { return new AxinDispatcherServlet(); } } 再调用一下 POST请求:
|
自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习
京ICP备14009008号-1@版权所有www.zixuephp.com
网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com