ERR_CONTENT_DECODING_FAILED, netty下载文件的压缩编码问题

说明: 本文涉及的netty源码都是netty4.1

问题描述

我在将netty整合到我自己依赖注入框架Yao中来作为web服务提供类似springmvc的能力的时候。先从官方demo开始。 整合Netty官方Demo HttpStaticFileServer的时候因为在channel中加入了HttpContentCompressor导致下载文件不成功。

表现的现象是浏览器下载状态码是200. 但是文件下载的内容就会失败,同时浏览器控制台显示ERR_CONTENT_DECODING_FAILED, 但是使用https协议的时候竟然可以下载。 并且服务端不会打印任何错误信息。

思考

因为控制台不打印错误,我又没有注意到浏览器控制台的ERR_CONTENT_DECODING_FAILED信息,但是官方的demo是正常的,我整合的就会有异常。所以我怀疑是我哪里加入了错误的handler。于是我一个个注释handler. 先从我自己的handler开始,最后终于确定了元凶HttpContentCompressor。 我去掉HttpContentCompressor就一切正常。

由此确定是Http协议的压缩编码问题,查看请求头发现请求头中Accept-Encoding字段正常传入值了,但是下载文件的时候压缩编码异常了。

此时我搜百度,发现这篇 https://www.sohu.com/a/190735418_684743文章。 终于找到原因了。

原因

HttpContentCompressor继承了HttpContentEncoder类。

从图中可以看到这个类只是处理HttpObject和HttpRequest类型的数据的压缩编码,而我们的demo中HttpStaticFileServerHandler中io.netty.example.http.file.HttpStaticFileServerHandler#channelRead0方法,
在这里插入图片描述
从图中可以看到, 它对于http和https协议使用了不同的方式下载文件,

  • 当使用https协议的时候往ctx中write的是HttpChunkedInput对象。
  • 使用http协议的时候往ctx中write中是DefaultFileRegion对象

正式由于这两种不同的方式导致http的方式下载文件失败。在下载文件的时候,response是分段发送的,

  1. 首先HttpHeader(实现了HttpObject)会先写入ctx, 到达HttpContentCompressor的时候, 会在响应头中加上content-encoding: gzip 。 源码在: io/netty/example/http/file/HttpStaticFileServerHandler.java:191
  2. 再次写入响应体的时候是DefaultFileRegion对象, DefaultFileRegion并没有继承HttpObject, 所以经过HttpContentCompressor的时候直接跳过,并不会进行压缩.
  3. 最后是LastHttpContent, 这个是空白的内容
    收到的响应请求头中content-encoding: gzip告诉浏览器响应是gzip压缩的,所以浏览器就会以gzip的方式去解压响应体, 解压失败浏览器控制台输出ERR_CONTENT_DECODING_FAILED

而HttpChunkedInput实现了httpObject接口,所以他结果HttpContentCompressor的时候正常压缩了,所以没有问题。

解决办法

1. 全部使用HttpChunkedInput下载文件

由于gzip压缩可以有效节约宽带, 所以我全部使用HttpChunkedInput的方式下载文件。

2. 去掉HttpContentCompressor压缩编码

去掉编码是最快捷的解决方式, 所有的http请求都不进行压缩

总结

  1. 通过HttpChunkedInput + HttpContentCompressor,可以实现压缩文件传输。当然,也可以自定义一个FileRegionCompressorHandler,根据客户端请求的Accept-Encoding,实现对文件内容的压缩,压缩之后,调用HttpServerResponseEncoder,对响应内容进行编码
  2. DefaultFileRegion实现了零拷贝的方式, 可以高效的传输文件
  3. 排查问题的时候, 不要忽略任何一个信息, 比如浏览器控制台的日志等, 要跟进源码查看
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值