【ZUUL】拦截器修改请求体后引出的 Content-Length 问题
背景
项目需求,对业务请求要进行拦截,并在请求体添加指定参数以进行请求合法性校验
实现方式和步骤
需求就是这么个需求了,然后就在 zuul 网关引入了一个 Filter,
在filter的 run 方法上,通过
RequestContext context = RequestContext.getCurrentContext(); HttpServletRequest request = context.getRequest();
拿到了 request
然后再通过
public static JSONObject getPostData(HttpServletRequest request) { StringBuilder data = new StringBuilder(); String line; BufferedReader reader; try { reader = request.getReader(); while (null != (line = reader.readLine())) { data.append(line); } } catch (IOException e) { return null; } if (data.length() > 0) { JSONObject requestBody = JSONObject.parseObject(data.toString()); return requestBody; } return new JSONObject(); } }
把 request 参数转成一个 json,
再然后往 json 里面加参数,
json 改变后,需要把修改后的请求体再回写到 request, 但因为 request 是不能改写的,所以又引入了: RequestWrapper 来进行对 request 进行重写
大概就是这样子:
request = new BodyRequestWrapper(request, requestBody.toString()); context.setRequest(request);
BodyRequestWrapper
public class BodyRequestWrapper extends HttpServletRequestWrapper { private String body; public BodyRequestWrapper(HttpServletRequest request, String context) { super(request); body = context; } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes("UTF-8")); ServletInputStream servletInputStream = new ServletInputStream() { @Override public int read() throws IOException { return byteArrayInputStream.read(); } @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener listener) { } }; return servletInputStream; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(this.getInputStream())); } }
至此第一阶段,就完工了,在本地测试了一下,嗯,还挺好,效果达到了。
问题
问题来了~
在本地测试都挺好的一个代码,一放到测试环境,诶,就不行了,
报错信息,大概就是请求参数解析错误,一个好好的请求参数,硬生生地只截取了一部分,造成 json 解析错误了。
继续定位
嗯。。。大概知道是 Content-Length 的问题了,但是这个 Content-Length 为什么会出问题呢,
一样的请求,之前也没毛病啊?
经过一翻思索,突然想起,不是修改了请求体参数吗!它的长度自然也跟着变化了,
嗯,然后再一查。。。找到了方案,
就是在 BodyRequestWrapper 这个类上,重写 getContentLength 和 getContentLengthLong 这两个方法,把请求体重新计算后再返回就好了。emmm, nice !
@Override public int getContentLength() { return body.length(); } @Override public long getContentLengthLong() { return body.length(); }
还是报错
修改一个版本后,满怀希望部署上去,一测,。。。。还是有问题! 还是一样的问题,这个长度还是不对!
怎么回事!
不是重写了这个长度的计算了吗!!!
emmm, 当时也是傻了,这里需要返回的根本不能按字符串长度去计算,应该按字节数组长度去返回才行。
于是,改成这样:
@Override public int getContentLength() { return body.getBytes().length; } @Override public long getContentLengthLong() { return body.getBytes().length; }
终于!!!好了啊!!泪目了。
小记一下,千万记得,程序里面计算长度,网络传输说的长度,都是字节流的长度啊。。。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
2022-04-04 maven 常用指令
2022-04-04 springboot常见报错