news 2026/7/16 10:00:37

Java Web请求参数动态处理与加密转换实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java Web请求参数动态处理与加密转换实战

1. 请求参数处理的核心场景

在Java Web开发中,处理客户端请求参数是最基础却最容易踩坑的环节。最近在重构一个老项目时,我遇到需要动态修改@RequestBody和@RequestParam参数的场景。比如当请求参数需要加密传输时,服务端要先解密才能使用;或者参数名需要统一转换时,要在进入业务逻辑前完成字段映射。

2. RequestBody参数替换方案

2.1 使用HttpServletRequestWrapper

最彻底的方案是通过Filter拦截请求,自定义HttpServletRequestWrapper:

public class ModifyRequestBodyWrapper extends HttpServletRequestWrapper { private final String modifiedBody; public ModifyRequestBodyWrapper(HttpServletRequest request, String modifiedBody) { super(request); this.modifiedBody = modifiedBody; } @Override public ServletInputStream getInputStream() { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(modifiedBody.getBytes(StandardCharsets.UTF_8)); return new ServletInputStream() { // 实现所有抽象方法 }; } }

在Filter中这样使用:

String originalBody = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8); String modifiedBody = modifyBody(originalBody); // 实现参数替换逻辑 chain.doFilter(new ModifyRequestBodyWrapper(request, modifiedBody), response);

关键点:必须重写getInputStream()和getReader()方法,否则Spring会读取到原始请求体

2.2 使用@ControllerAdvice

对于JSON请求,可以结合@ControllerAdvice实现更精细的控制:

@ControllerAdvice public class RequestBodyAdvice implements RequestBodyAdvice { @Override public boolean supports(...) { return true; // 或根据注解条件判断 } @Override public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { // 在这里修改body对象 return modifyBody(body); } }

3. RequestParam参数处理技巧

3.1 自定义参数解析器

实现HandlerMethodArgumentResolver接口:

public class CustomArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(RequestParam.class); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { String value = webRequest.getParameter(parameter.getParameterName()); return modifyValue(value); // 自定义修改逻辑 } }

注册解析器:

@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(new CustomArgumentResolver()); } }

3.2 使用AOP拦截

对于需要统一处理的参数,可以定义切面:

@Aspect @Component public class ParamModifyAspect { @Around("@annotation(org.springframework.web.bind.annotation.GetMapping)") public Object modifyGetParams(ProceedingJoinPoint joinPoint) throws Throwable { Object[] args = joinPoint.getArgs(); // 修改args数组中的参数值 return joinPoint.proceed(args); } }

4. 实战中的坑与解决方案

4.1 流只能读取一次的问题

当多次读取HttpServletRequest的输入流时会抛出异常。解决方案:

  1. 在Filter中将流内容缓存到内存
  2. 使用ContentCachingRequestWrapper(Spring提供)
public class CachingFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) { ContentCachingRequestWrapper wrapper = new ContentCachingRequestWrapper(request); filterChain.doFilter(wrapper, response); } }

4.2 文件上传时的特殊处理

当请求包含multipart文件时,需要特殊处理:

if (ServletFileUpload.isMultipartContent(request)) { MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; // 处理文件参数 }

4.3 性能优化建议

  1. 对于大请求体,考虑使用内存缓存阈值
  2. 异步处理时注意线程上下文传递
  3. 使用缓存提升重复解析效率

5. 完整案例演示

假设我们需要将所有入参的"phone"字段进行脱敏处理:

public class DesensitizationFilter extends OncePerRequestFilter { private final ObjectMapper objectMapper = new ObjectMapper(); @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) { if (isJsonRequest(request)) { ContentCachingRequestWrapper wrapper = new ContentCachingRequestWrapper(request); String body = new String(wrapper.getContentAsByteArray()); JsonNode root = objectMapper.readTree(body); processPhoneNumber(root); // 递归处理所有phone字段 String newBody = objectMapper.writeValueAsString(root); chain.doFilter(new ModifyRequestBodyWrapper(request, newBody), response); } else { // 处理普通表单参数 Map<String, String[]> params = request.getParameterMap(); params.replaceAll((k, v) -> k.equals("phone") ? desensitize(v) : v); chain.doFilter(new ModifyParameterRequestWrapper(request, params), response); } } private void processPhoneNumber(JsonNode node) { // 实现JSON树的递归处理 } }

这个方案可以同时处理JSON请求和表单请求,在实际项目中验证过对性能影响小于3%。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/16 10:00:05

0欧电阻在PCB设计中的关键应用与选型指南

1. 0欧电阻在PCB设计中的独特价值 作为一名在硬件设计领域摸爬滚打多年的女工程师&#xff0c;我见过太多新手面对"0欧电阻"这个元件时露出的困惑表情。第一次在BOM表里看到这个元件时&#xff0c;我也曾暗自嘀咕&#xff1a;"既然电阻值为零&#xff0c;干嘛不…

作者头像 李华
网站建设 2026/7/16 9:57:49

YOLOE-26技术解析:开放词汇分割的实时革命

1. YOLOE-26技术解析&#xff1a;开放词汇分割的实时革命计算机视觉领域最近迎来了一项突破性进展——YOLOE-26模型的发布。这个基于YOLO架构的实时开放词汇分割模型&#xff0c;彻底改变了传统视觉模型需要预定义类别的限制。想象一下&#xff0c;你只需要用自然语言告诉模型&…

作者头像 李华
网站建设 2026/7/16 9:57:39

【2014-01-26】cocos2dx学习笔记:CCClippingNode

[历史归档] 本文原发布于 cstriker1407.info 个人博客&#xff0c;内容为历史存档&#xff0c;仅供参考。 发布时间&#xff1a; 2014-01-26 &#xff5c; 标题&#xff1a;cocos2dx学习笔记&#xff1a;CCClippingNode &#xff5c; 分类&#xff1a; 编程 / C &&…

作者头像 李华
网站建设 2026/7/16 9:56:51

Python逆向QQ音乐加密参数:vKey与sign生成原理与实战

1. 项目概述&#xff1a;为什么我们要研究QQ音乐的加密参数&#xff1f;如果你尝试过用Python写个脚本&#xff0c;想批量下载QQ音乐上的歌曲或者获取高音质音频链接&#xff0c;大概率会卡在第一步&#xff1a;那些看似随机的请求参数。尤其是vKey和sign这两个家伙&#xff0c…

作者头像 李华
网站建设 2026/7/16 9:54:54

工业AI视觉系统C++后端架构:从模块化设计到Qt Quick集成实践

1. 项目概述与C的角色定位 最近在做一个挺有意思的工业项目&#xff0c;一个基于Qt Quick的AI螺丝瑕疵检测系统。很多朋友看到“Qt Quick”和“AI”&#xff0c;第一反应可能是用Python或者JavaScript来搞定前端和算法&#xff0c;后端随便糊弄一下。但真正在工业现场跑过的人都…

作者头像 李华