diff --git a/hutool-http/pom.xml b/hutool-http/pom.xml index 63a4a7dc3..d858816a9 100755 --- a/hutool-http/pom.xml +++ b/hutool-http/pom.xml @@ -22,6 +22,12 @@ hutool-core ${project.parent.version} + + javax.xml.soap + javax.xml.soap-api + 1.4.0 + provided + cn.hutool hutool-json @@ -29,10 +35,10 @@ test - javax.xml.soap - javax.xml.soap-api - 1.4.0 - provided + org.brotli + dec + 0.1.2 + test diff --git a/hutool-http/src/main/java/cn/hutool/http/GlobalCompressStreamRegister.java b/hutool-http/src/main/java/cn/hutool/http/GlobalCompressStreamRegister.java new file mode 100755 index 000000000..a0d13a9f3 --- /dev/null +++ b/hutool-http/src/main/java/cn/hutool/http/GlobalCompressStreamRegister.java @@ -0,0 +1,57 @@ +package cn.hutool.http; + +import cn.hutool.core.map.CaseInsensitiveMap; + +import java.io.InputStream; +import java.util.Map; + +/** + * 全局响应内容压缩解压器注册中心
+ * 通过注册指定Accept-Encoding的流,来包装响应内容流,从而支持特殊压缩算法 + * + * @author looly + * @since 6.0.0 + */ +public enum GlobalCompressStreamRegister { + /** + * 单例对象 + */ + INSTANCE; + + /** + * 存储内容压缩流信息 + */ + private final Map> compressMap = new CaseInsensitiveMap<>(); + + GlobalCompressStreamRegister() { + } + + /** + * 获取解压器 + * + * @param contentEncoding Accept-Encoding名称,如gzip、defalte、br等,不区分大小写 + * @return 解压器 + */ + public Class get(final String contentEncoding) { + return compressMap.get(contentEncoding); + } + + /** + * 注册解压器 + * + * @param contentEncoding Accept-Encoding名称,如gzip、defalte、br等,不区分大小写 + * @param streamClass 解压类 + */ + synchronized public void register(final String contentEncoding, final Class streamClass) { + this.compressMap.put(contentEncoding, streamClass); + } + + /** + * 注销压缩器 + * + * @param contentEncoding Accept-Encoding名称,如gzip、defalte、br等,不区分大小写 + */ + synchronized public void unRegister(final String contentEncoding) { + this.compressMap.remove(contentEncoding); + } +} diff --git a/hutool-http/src/main/java/cn/hutool/http/GlobalHeaders.java b/hutool-http/src/main/java/cn/hutool/http/GlobalHeaders.java index 59f8590da..f3e6d539b 100644 --- a/hutool-http/src/main/java/cn/hutool/http/GlobalHeaders.java +++ b/hutool-http/src/main/java/cn/hutool/http/GlobalHeaders.java @@ -18,6 +18,9 @@ import java.util.Map.Entry; * @author looly */ public enum GlobalHeaders { + /** + * 单例对象 + */ INSTANCE; /** diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpInputStream.java b/hutool-http/src/main/java/cn/hutool/http/HttpInputStream.java index d7374b752..a26dcae34 100644 --- a/hutool-http/src/main/java/cn/hutool/http/HttpInputStream.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpInputStream.java @@ -1,5 +1,6 @@ package cn.hutool.http; +import cn.hutool.core.reflect.ConstructorUtil; import cn.hutool.core.text.StrUtil; import java.io.ByteArrayInputStream; @@ -92,17 +93,27 @@ public class HttpInputStream extends InputStream { return; } - if (response.isGzip() && false == (response.in instanceof GZIPInputStream)) { + final String contentEncoding = response.contentEncoding(); + if (StrUtil.equalsIgnoreCase("gzip", contentEncoding) && false == (response.in instanceof GZIPInputStream)) { // Accept-Encoding: gzip try { this.in = new GZIPInputStream(this.in); - } catch (final IOException e) { + } catch (final IOException ignore) { // 在类似于Head等方法中无body返回,此时GZIPInputStream构造会出现错误,在此忽略此错误读取普通数据 // ignore } - } else if (response.isDeflate() && false == (this.in instanceof InflaterInputStream)) { + } else if (StrUtil.equalsIgnoreCase("deflate", contentEncoding) && false == (this.in instanceof InflaterInputStream)) { // Accept-Encoding: defalte this.in = new InflaterInputStream(this.in, new Inflater(true)); + } else{ + final Class streamClass = GlobalCompressStreamRegister.INSTANCE.get(contentEncoding); + if(null != streamClass){ + try { + this.in = ConstructorUtil.newInstance(streamClass, this.in); + } catch (final Exception ignore) { + // 对于构造错误的压缩算法,跳过之 + } + } } } } diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpResponse.java b/hutool-http/src/main/java/cn/hutool/http/HttpResponse.java index 9f35ba946..078eaf700 100755 --- a/hutool-http/src/main/java/cn/hutool/http/HttpResponse.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpResponse.java @@ -143,27 +143,6 @@ public class HttpResponse extends HttpBase implements Closeable { return contentLength; } - /** - * 是否为gzip压缩过的内容 - * - * @return 是否为gzip压缩过的内容 - */ - public boolean isGzip() { - final String contentEncoding = contentEncoding(); - return "gzip".equalsIgnoreCase(contentEncoding); - } - - /** - * 是否为zlib(Deflate)压缩过的内容 - * - * @return 是否为zlib(Deflate)压缩过的内容 - * @since 4.5.7 - */ - public boolean isDeflate() { - final String contentEncoding = contentEncoding(); - return "deflate".equalsIgnoreCase(contentEncoding); - } - /** * 是否为Transfer-Encoding:Chunked的内容 * diff --git a/hutool-http/src/test/java/cn/hutool/http/IssueI5XBCFTest.java b/hutool-http/src/test/java/cn/hutool/http/IssueI5XBCFTest.java new file mode 100755 index 000000000..923884cc3 --- /dev/null +++ b/hutool-http/src/test/java/cn/hutool/http/IssueI5XBCFTest.java @@ -0,0 +1,20 @@ +package cn.hutool.http; + +import cn.hutool.core.lang.Console; +import org.brotli.dec.BrotliInputStream; +import org.junit.Ignore; +import org.junit.Test; + +public class IssueI5XBCFTest { + + @Test + @Ignore + public void getTest() { + GlobalCompressStreamRegister.INSTANCE.register("br", BrotliInputStream.class); + + final HttpResponse s = HttpUtil.createGet("https://static-exp1.licdn.com/sc/h/br/1cp0oqz322bdprj3qd4pojqix") + .header(Header.ACCEPT_ENCODING, "br") + .execute(); + Console.log(s.body()); + } +}