巴音郭楞蒙古自治州网站建设_网站建设公司_测试上线_seo优化
2026/1/22 16:11:41 网站建设 项目流程

在现代Web应用开发中,我们经常需要在请求到达最终处理器之前对请求数据进行动态修改。本文将介绍如何使用Spring的SpEL(Spring Expression Language)表达式来动态修改HTTP请求的参数和请求体,并通过一个完整的示例展示实现过程。

整体架构概述

整个解决方案的核心流程包括:

1. HandlerInterceptor拦截请求

使用Spring的HandlerInterceptor接口来拦截请求,在请求被实际处理前进行预处理:

publicclassSmartRouterInterceptorimplementsHandlerInterceptor{privatefinalSmartRouterManagersmartRouterManager;publicSmartRouterInterceptor(SmartRouterManagersmartRouterManager){this.smartRouterManager=smartRouterManager;}@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{returnsmartRouterManager.rule(request,response);}}

SmartRouterInterceptor作为拦截器,将请求交给SmartRouterManager进行规则处理,这是整个流程的入口点。

2. 重新封装HttpServletRequestWrapper以支持请求体反复读取

由于HTTP请求体只能被读取一次,我们需要创建一个可变的请求包装器来支持多次读取和修改:

publicclassMutableHttpServletRequestWrapperextendsHttpServletRequestWrapper{privateMap<String,String[]>modifiedParams=newHashMap<>();privatebyte[]modifiedBody;privateBufferedReaderbodyReader;publicMutableHttpServletRequestWrapper(HttpServletRequestrequest)throwsIOException{super(request);// 复制原始参数modifiedParams.putAll(request.getParameterMap());// 读取并缓存原始请求体if(isRequestBodySupported(request)){InputStreaminputStream=request.getInputStream();modifiedBody=StreamUtils.copyToByteArray(inputStream);bodyReader=newBufferedReader(newInputStreamReader(newByteArrayInputStream(modifiedBody),StandardCharsets.UTF_8));}}@OverridepublicServletInputStreamgetInputStream()throwsIOException{if(modifiedBody==null){returnsuper.getInputStream();}finalByteArrayInputStreambyteArrayInputStream=newByteArrayInputStream(modifiedBody);returnnewServletInputStream(){@OverridepublicbooleanisFinished(){returnbyteArrayInputStream.available()==0;}@OverridepublicbooleanisReady(){returntrue;}@OverridepublicvoidsetReadListener(ReadListenerreadListener){}@Overridepublicintread()throwsIOException{returnbyteArrayInputStream.read();}};}// 其他重写方法...}

这个包装器类解决了原生HttpServletRequest只能读取一次请求体的问题,通过缓存机制实现了请求体的重复读取。

3. 使用SpEL表达式修改参数和请求体

核心功能是使用SpEL表达式来动态修改请求数据:

@UtilityClasspublicclassSpelParamModifier{privatestaticfinalExpressionParserPARSER=newSpelExpressionParser();publicvoidmodifyParam(Map<String,String[]>params,StringspelExpression){StandardEvaluationContextcontext=newStandardEvaluationContext();context.setVariable("params",params);PARSER.parseExpression(spelExpression).getValue(context);}publicvoidmodifyJsonBody(Map<String,Object>params,StringspelExpression){StandardEvaluationContextcontext=newStandardEvaluationContext();context.setVariable("params",params);PARSER.parseExpression(spelExpression).getValue(context);}}

SmartRouterManager中集成这些组件:

if(StringUtils.hasText(mapRule)||StringUtils.hasText(bodyRule)){MutableHttpServletRequestWrappermutableRequest=newMutableHttpServletRequestWrapper(request);if(StringUtils.hasText(mapRule)){Map<String,String[]>modifiedMap=newHashMap<>(mutableRequest.getParameterMap());SpelParamModifier.modifyParam(modifiedMap,mapRule);modifiedMap.forEach(mutableRequest::setParameter);}if(StringUtils.hasText(bodyRule)){StringoriginalBody=StreamUtils.copyToString(mutableRequest.getInputStream(),StandardCharsets.UTF_8);Map<String,Object>bodyMap=OBJECT_MAPPER.readValue(originalBody,Map.class);SpelParamModifier.modifyJsonBody(bodyMap,bodyRule);StringmodifiedBody=OBJECT_MAPPER.writeValueAsString(bodyMap);mutableRequest.setJsonBody(modifiedBody);}request=mutableRequest;}

实际应用场景

这种设计模式特别适用于以下场景:

  • API网关:在请求转发前修改请求参数或请求体
  • 路由规则:根据不同条件动态修改请求内容
  • 参数验证和清理:在业务逻辑处理前统一修改请求数据
  • A/B测试:根据规则动态修改请求参数进行实验

总结

通过结合使用HandlerInterceptorHttpServletRequestWrapper和SpEL表达式,我们可以创建一个灵活的请求处理系统,能够在运行时动态修改HTTP请求的参数和请求体。这种方案提供了高度的灵活性和可扩展性,使得我们能够根据业务需求编写复杂的请求修改规则。


示例代码地址:

Gitee

Github

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询