2026/3/27 3:18:59
网站建设
项目流程
实验室网站建设,微信小程序制作宣传页,wordpress 百度云网盘,北京学会网站建设在现代Web应用开发中#xff0c;我们经常需要在请求到达最终处理器之前对请求数据进行动态修改。本文将介绍如何使用Spring的SpEL#xff08;Spring Expression Language#xff09;表达式来动态修改HTTP请求的参数和请求体#xff0c;并通过一个完整的示例展示实现过程。 …在现代Web应用开发中我们经常需要在请求到达最终处理器之前对请求数据进行动态修改。本文将介绍如何使用Spring的SpELSpring Expression Language表达式来动态修改HTTP请求的参数和请求体并通过一个完整的示例展示实现过程。整体架构概述整个解决方案的核心流程包括1. HandlerInterceptor拦截请求使用Spring的HandlerInterceptor接口来拦截请求在请求被实际处理前进行预处理publicclassSmartRouterInterceptorimplementsHandlerInterceptor{privatefinalSmartRouterManagersmartRouterManager;publicSmartRouterInterceptor(SmartRouterManagersmartRouterManager){this.smartRouterManagersmartRouterManager;}OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{returnsmartRouterManager.rule(request,response);}}SmartRouterInterceptor作为拦截器将请求交给SmartRouterManager进行规则处理这是整个流程的入口点。2. 重新封装HttpServletRequestWrapper以支持请求体反复读取由于HTTP请求体只能被读取一次我们需要创建一个可变的请求包装器来支持多次读取和修改publicclassMutableHttpServletRequestWrapperextendsHttpServletRequestWrapper{privateMapString,String[]modifiedParamsnewHashMap();privatebyte[]modifiedBody;privateBufferedReaderbodyReader;publicMutableHttpServletRequestWrapper(HttpServletRequestrequest)throwsIOException{super(request);// 复制原始参数modifiedParams.putAll(request.getParameterMap());// 读取并缓存原始请求体if(isRequestBodySupported(request)){InputStreaminputStreamrequest.getInputStream();modifiedBodyStreamUtils.copyToByteArray(inputStream);bodyReadernewBufferedReader(newInputStreamReader(newByteArrayInputStream(modifiedBody),StandardCharsets.UTF_8));}}OverridepublicServletInputStreamgetInputStream()throwsIOException{if(modifiedBodynull){returnsuper.getInputStream();}finalByteArrayInputStreambyteArrayInputStreamnewByteArrayInputStream(modifiedBody);returnnewServletInputStream(){OverridepublicbooleanisFinished(){returnbyteArrayInputStream.available()0;}OverridepublicbooleanisReady(){returntrue;}OverridepublicvoidsetReadListener(ReadListenerreadListener){}Overridepublicintread()throwsIOException{returnbyteArrayInputStream.read();}};}// 其他重写方法...}这个包装器类解决了原生HttpServletRequest只能读取一次请求体的问题通过缓存机制实现了请求体的重复读取。3. 使用SpEL表达式修改参数和请求体核心功能是使用SpEL表达式来动态修改请求数据UtilityClasspublicclassSpelParamModifier{privatestaticfinalExpressionParserPARSERnewSpelExpressionParser();publicvoidmodifyParam(MapString,String[]params,StringspelExpression){StandardEvaluationContextcontextnewStandardEvaluationContext();context.setVariable(params,params);PARSER.parseExpression(spelExpression).getValue(context);}publicvoidmodifyJsonBody(MapString,Objectparams,StringspelExpression){StandardEvaluationContextcontextnewStandardEvaluationContext();context.setVariable(params,params);PARSER.parseExpression(spelExpression).getValue(context);}}在SmartRouterManager中集成这些组件if(StringUtils.hasText(mapRule)||StringUtils.hasText(bodyRule)){MutableHttpServletRequestWrappermutableRequestnewMutableHttpServletRequestWrapper(request);if(StringUtils.hasText(mapRule)){MapString,String[]modifiedMapnewHashMap(mutableRequest.getParameterMap());SpelParamModifier.modifyParam(modifiedMap,mapRule);modifiedMap.forEach(mutableRequest::setParameter);}if(StringUtils.hasText(bodyRule)){StringoriginalBodyStreamUtils.copyToString(mutableRequest.getInputStream(),StandardCharsets.UTF_8);MapString,ObjectbodyMapOBJECT_MAPPER.readValue(originalBody,Map.class);SpelParamModifier.modifyJsonBody(bodyMap,bodyRule);StringmodifiedBodyOBJECT_MAPPER.writeValueAsString(bodyMap);mutableRequest.setJsonBody(modifiedBody);}requestmutableRequest;}实际应用场景这种设计模式特别适用于以下场景API网关在请求转发前修改请求参数或请求体路由规则根据不同条件动态修改请求内容参数验证和清理在业务逻辑处理前统一修改请求数据A/B测试根据规则动态修改请求参数进行实验总结通过结合使用HandlerInterceptor、HttpServletRequestWrapper和SpEL表达式我们可以创建一个灵活的请求处理系统能够在运行时动态修改HTTP请求的参数和请求体。这种方案提供了高度的灵活性和可扩展性使得我们能够根据业务需求编写复杂的请求修改规则。示例代码地址GiteeGithub