add HttpInputStream

This commit is contained in:
Looly
2019-08-16 15:04:42 +08:00
parent 6b011af032
commit 9e39667e5a
10 changed files with 174 additions and 50 deletions

View File

@@ -0,0 +1,111 @@
package cn.hutool.http;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.DeflaterInputStream;
import java.util.zip.GZIPInputStream;
import cn.hutool.core.util.StrUtil;
/**
* HTTP输入流此流用于包装Http请求响应内容的流用于解析各种压缩、分段的响应流内容
*
* @author Looly
*
*/
public class HttpInputStream extends InputStream {
/** 原始流 */
private volatile InputStream in;
/**
* 构造
*
* @param response 响应对象
*/
public HttpInputStream(HttpResponse response) {
init(response);
}
@Override
public int read() throws IOException {
return this.in.read();
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
return this.in.read(b, off, len);
}
@Override
public long skip(long n) throws IOException {
return this.in.skip(n);
}
@Override
public int available() throws IOException {
return this.in.available();
}
@Override
public void close() throws IOException {
this.in.close();
}
@Override
public synchronized void mark(int readlimit) {
this.in.mark(readlimit);
}
@Override
public synchronized void reset() throws IOException {
this.in.reset();
}
@Override
public boolean markSupported() {
return this.in.markSupported();
}
/**
* 初始化流
*
* @param response 响应对象
*/
private void init(HttpResponse response) {
try {
this.in = (response.status < HttpStatus.HTTP_BAD_REQUEST) ? response.httpConnection.getInputStream() : response.httpConnection.getErrorStream();
} catch (IOException e) {
if (e instanceof FileNotFoundException) {
// 服务器无返回内容,忽略之
} else {
throw new HttpException(e);
}
}
// 在一些情况下返回的流为null此时提供状态码说明
if (null == this.in) {
this.in = new ByteArrayInputStream(StrUtil.format("Error request, response status: {}", response.status).getBytes());
return;
}
// TODO 分段响应内容解析
if(response.isChunked()) {
}
if (response.isGzip() && false == (response.in instanceof GZIPInputStream)) {
// Accept-Encoding: gzip
try {
this.in = new GZIPInputStream(this.in);
} catch (IOException e) {
// 在类似于Head等方法中无body返回此时GZIPInputStream构造会出现错误在此忽略此错误读取普通数据
// ignore
}
} else if (response.isDeflate() && false == (this.in instanceof DeflaterInputStream)) {
// Accept-Encoding: defalte
this.in = new DeflaterInputStream(this.in);
}
}
}

View File

@@ -12,8 +12,6 @@ import java.net.HttpCookie;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map.Entry;
import java.util.zip.DeflaterInputStream;
import java.util.zip.GZIPInputStream;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FastByteArrayOutputStream;
@@ -38,13 +36,13 @@ import cn.hutool.log.StaticLog;
public class HttpResponse extends HttpBase<HttpResponse> implements Closeable {
/** 持有连接对象 */
private HttpConnection httpConnection;
protected HttpConnection httpConnection;
/** Http请求原始流 */
private InputStream in;
protected InputStream in;
/** 是否异步异步下只持有流否则将在初始化时直接读取body内容 */
private volatile boolean isAsync;
/** 响应状态码 */
private int status;
protected int status;
/** 是否忽略读取Http响应体 */
private boolean ignoreBody;
/** 从响应中获取的编码 */
@@ -373,9 +371,9 @@ public class HttpResponse extends HttpBase<HttpResponse> implements Closeable {
* @throws HttpException IO异常
*/
private HttpResponse init() throws HttpException {
// 获取响应状态码
try {
this.status = httpConnection.responseCode();
this.in = (this.status < HttpStatus.HTTP_BAD_REQUEST) ? this.httpConnection.getInputStream() : this.httpConnection.getErrorStream();
} catch (IOException e) {
if (e instanceof FileNotFoundException) {
// 服务器无返回内容,忽略之
@@ -394,31 +392,15 @@ public class HttpResponse extends HttpBase<HttpResponse> implements Closeable {
// 存储服务端设置的Cookie信息
GlobalCookieManager.store(httpConnection);
// 获取响应编码
final Charset charset = httpConnection.getCharset();
this.charsetFromResponse = charset;
if (null != charset) {
this.charset = charset;
}
if (null == this.in) {
// 在一些情况下返回的流为null此时提供状态码说明
this.in = new ByteArrayInputStream(StrUtil.format("Error request, response status: {}", this.status).getBytes());
} else {
// TODO 分段响应内容解析
if (isGzip() && false == (in instanceof GZIPInputStream)) {
// Accept-Encoding: gzip
try {
in = new GZIPInputStream(in);
} catch (IOException e) {
// 在类似于Head等方法中无body返回此时GZIPInputStream构造会出现错误在此忽略此错误读取普通数据
// ignore
}
} else if (isDeflate() && false == (in instanceof DeflaterInputStream)) {
// Accept-Encoding: defalte
in = new DeflaterInputStream(in);
}
}
// 获取响应内容流
this.in = new HttpInputStream(this);
// 同步情况下强制同步
return this.isAsync ? this : forceSync();

View File

@@ -63,7 +63,8 @@ public class HttpUtilTest {
@Test
@Ignore
public void getTest5() {
String res = HttpUtil.get("https://comment.bilibili.com/67573272.xml");
String res = HttpRequest.get("https://comment.bilibili.com/67573272.xml")
.execute().body();
Console.log(res);
}