diff --git a/hutool-core/src/main/java/cn/hutool/core/io/stream/SyncInputStream.java b/hutool-core/src/main/java/cn/hutool/core/io/stream/SyncInputStream.java new file mode 100755 index 000000000..08b22c990 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/io/stream/SyncInputStream.java @@ -0,0 +1,112 @@ +package cn.hutool.core.io.stream; + +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.io.StreamProgress; +import cn.hutool.core.text.StrUtil; + +import java.io.ByteArrayInputStream; +import java.io.EOFException; +import java.io.FileNotFoundException; +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * 同步流,可将包装的流同步为ByteArrayInputStream,以便持有内容并关闭原流 + * + * @author looly + * @since 6.0.0 + */ +public class SyncInputStream extends FilterInputStream { + + private final long length; + private final boolean isIgnoreEOFError; + /** + * 是否异步,异步下只持有流,否则将在初始化时直接读取body内容 + */ + private volatile boolean asyncFlag = true; + + /** + * 构造
+ * 如果isAsync为{@code true},则直接持有原有流,{@code false},则将流中内容,按照给定length读到{@link ByteArrayInputStream}中备用 + * + * @param in 数据流 + * @param length 限定长度,-1表示未知长度 + * @param isAsync 是否异步 + * @param isIgnoreEOFError 是否忽略EOF错误,在Http协议中,对于Transfer-Encoding: Chunked在正常情况下末尾会写入一个Length为0的的chunk标识完整结束
+ * 如果服务端未遵循这个规范或响应没有正常结束,会报EOF异常,此选项用于是否忽略这个异常。
+ */ + public SyncInputStream(final InputStream in, final long length, final boolean isAsync, final boolean isIgnoreEOFError) { + super(in); + this.length = length; + this.isIgnoreEOFError = isIgnoreEOFError; + if (false == isAsync) { + sync(); + } + } + + /** + * 同步数据到内存 + */ + public void sync() { + if (false == asyncFlag) { + // 已经是同步模式 + return; + } + + this.in = new ByteArrayInputStream(readBytes()); + this.asyncFlag = false; + } + + /** + * 读取流中所有bytes + * + * @return bytes + */ + public byte[] readBytes() { + final FastByteArrayOutputStream bytesOut = new FastByteArrayOutputStream(length > 0 ? (int)length : 1024); + final long length = copyTo(bytesOut, null); + return length > 0 ? bytesOut.toByteArray() : new byte[0]; + } + + /** + * 将流的内容拷贝到输出流 + * @param out 输出流 + * @param streamProgress 进度条 + * @return 拷贝长度 + */ + public long copyTo(final OutputStream out, final StreamProgress streamProgress){ + long copyLength = -1; + try { + copyLength = IoUtil.copy(this.in, out, IoUtil.DEFAULT_BUFFER_SIZE, this.length, streamProgress); + } catch (final IORuntimeException e) { + if (false == (isIgnoreEOFError && isEOFException(e.getCause()))) { + throw e; + } + // 忽略读取流中的EOF错误 + }finally { + // 读取结束 + IoUtil.close(in); + } + return copyLength; + } + + /** + * 是否为EOF异常,包括
+ * + * + * @param e 异常 + * @return 是否EOF异常 + */ + private static boolean isEOFException(final Throwable e) { + if (e instanceof FileNotFoundException) { + // 服务器无返回内容,忽略之 + return true; + } + return e instanceof EOFException || StrUtil.containsIgnoreCase(e.getMessage(), "Premature EOF"); + } +} diff --git a/hutool-http/pom.xml b/hutool-http/pom.xml index d4d2c26ef..b3e67831f 100755 --- a/hutool-http/pom.xml +++ b/hutool-http/pom.xml @@ -73,5 +73,11 @@ 1.7.25 test + + com.squareup.okhttp3 + mockwebserver + 4.10.0 + test + diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java b/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java index c6852b90f..03aa7d0d0 100755 --- a/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java @@ -704,7 +704,7 @@ public class HttpUtil { * @param conn HTTP连接对象 * @return 字符集 */ - public static String getCharset(final HttpURLConnection conn) { + public static Charset getCharset(final HttpURLConnection conn) { if (conn == null) { return null; } @@ -719,7 +719,19 @@ public class HttpUtil { * @return 字符集 * @since 5.2.6 */ - public static String getCharset(final String contentType) { + public static Charset getCharset(final String contentType) { + return CharsetUtil.parse(getCharsetName(contentType), null); + } + + /** + * 从Http连接的头信息中获得字符集
+ * 从ContentType中获取 + * + * @param contentType Content-Type + * @return 字符集 + * @since 5.2.6 + */ + public static String getCharsetName(final String contentType) { if (StrUtil.isBlank(contentType)) { return null; } diff --git a/hutool-http/src/main/java/cn/hutool/http/client/Response.java b/hutool-http/src/main/java/cn/hutool/http/client/Response.java index b6e74878d..b8c59c4b6 100755 --- a/hutool-http/src/main/java/cn/hutool/http/client/Response.java +++ b/hutool-http/src/main/java/cn/hutool/http/client/Response.java @@ -1,7 +1,6 @@ package cn.hutool.http.client; import cn.hutool.core.convert.Convert; -import cn.hutool.core.io.IoUtil; import cn.hutool.core.text.StrUtil; import cn.hutool.http.HttpException; import cn.hutool.http.HttpUtil; @@ -37,11 +36,13 @@ public interface Response extends Closeable { String header(final String name); /** - * 获取字符集编码 + * 获取字符集编码,默认为响应头中的编码 * * @return 字符集 */ - Charset charset(); + default Charset charset(){ + return HttpUtil.getCharset(header(Header.CONTENT_TYPE)); + } /** * 获得服务区响应流
@@ -56,7 +57,7 @@ public interface Response extends Closeable { * @return {@link ResponseBody} */ default ResponseBody body(){ - return new ResponseBody(this, true); + return new ResponseBody(this, bodyStream(), false, true); } /** @@ -76,7 +77,7 @@ public interface Response extends Closeable { * @return byte[] */ default byte[] bodyBytes() { - return IoUtil.readBytes(bodyStream()); + return body().getBytes(); } /** diff --git a/hutool-http/src/main/java/cn/hutool/http/client/body/ResponseBody.java b/hutool-http/src/main/java/cn/hutool/http/client/body/ResponseBody.java index 3a2510771..ae5d3f3a8 100755 --- a/hutool-http/src/main/java/cn/hutool/http/client/body/ResponseBody.java +++ b/hutool-http/src/main/java/cn/hutool/http/client/body/ResponseBody.java @@ -1,10 +1,10 @@ package cn.hutool.http.client.body; import cn.hutool.core.io.FileUtil; -import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.StreamProgress; import cn.hutool.core.io.file.FileNameUtil; +import cn.hutool.core.io.stream.SyncInputStream; import cn.hutool.core.lang.Assert; import cn.hutool.core.regex.ReUtil; import cn.hutool.core.text.StrUtil; @@ -13,8 +13,9 @@ import cn.hutool.http.HttpException; import cn.hutool.http.client.Response; import cn.hutool.http.meta.Header; -import java.io.EOFException; +import java.io.Closeable; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -23,25 +24,25 @@ import java.io.OutputStream; * * @author looly */ -public class ResponseBody implements HttpBody { +public class ResponseBody implements HttpBody, Closeable { private final Response response; /** - * 是否忽略响应读取时可能的EOF异常。
- * 在Http协议中,对于Transfer-Encoding: Chunked在正常情况下末尾会写入一个Length为0的的chunk标识完整结束。
- * 如果服务端未遵循这个规范或响应没有正常结束,会报EOF异常,此选项用于是否忽略这个异常。 + * Http请求原始流 */ - private final boolean isIgnoreEOFError; + private final SyncInputStream bodyStream; /** * 构造 * * @param response 响应体 + * @param in HTTP主体响应流 + * @param isAsync 是否异步模式 * @param isIgnoreEOFError 是否忽略EOF错误 */ - public ResponseBody(final Response response, final boolean isIgnoreEOFError) { + public ResponseBody(final Response response, final InputStream in, final boolean isAsync, final boolean isIgnoreEOFError) { this.response = response; - this.isIgnoreEOFError = isIgnoreEOFError; + this.bodyStream = new SyncInputStream(in, response.contentLength(), isAsync, isIgnoreEOFError); } @Override @@ -51,7 +52,7 @@ public class ResponseBody implements HttpBody { @Override public InputStream getStream() { - return response.bodyStream(); + return this.bodyStream; } @Override @@ -59,6 +60,25 @@ public class ResponseBody implements HttpBody { write(out, false, null); } + /** + * 同步数据到内存,以bytes形式存储 + * + * @return this + */ + public ResponseBody sync() { + this.bodyStream.sync(); + return this; + } + + /** + * 获取响应内容的bytes + * + * @return 响应内容bytes + */ + public byte[] getBytes() { + return this.bodyStream.readBytes(); + } + /** * 将响应内容写出到{@link OutputStream}
* 异步模式下直接读取Http流写出,同步模式下将存储在内存中的响应内容写出
@@ -72,9 +92,8 @@ public class ResponseBody implements HttpBody { */ public long write(final OutputStream out, final boolean isCloseOut, final StreamProgress streamProgress) { Assert.notNull(out, "[out] must be not null!"); - final long contentLength = response.contentLength(); try { - return copyBody(getStream(), out, contentLength, streamProgress, isIgnoreEOFError); + return this.bodyStream.copyTo(out, streamProgress); } finally { if (isCloseOut) { IoUtil.close(out); @@ -165,6 +184,11 @@ public class ResponseBody implements HttpBody { return outFile; } + @Override + public void close() throws IOException { + this.bodyStream.close(); + } + // region ---------------------------------------------------------------------------- Private Methods /** @@ -207,37 +231,5 @@ public class ResponseBody implements HttpBody { } return fileName; } - - /** - * 将响应内容写出到{@link OutputStream}
- * 异步模式下直接读取Http流写出,同步模式下将存储在内存中的响应内容写出
- * 写出后会关闭Http流(异步模式) - * - * @param in 输入流 - * @param out 写出的流 - * @param contentLength 总长度,-1表示未知 - * @param streamProgress 进度显示接口,通过实现此接口显示下载进度 - * @param isIgnoreEOFError 是否忽略响应读取时可能的EOF异常 - * @return 拷贝长度 - */ - private static long copyBody(final InputStream in, final OutputStream out, final long contentLength, final StreamProgress streamProgress, final boolean isIgnoreEOFError) { - if (null == out) { - throw new NullPointerException("[out] is null!"); - } - - long copyLength = -1; - try { - copyLength = IoUtil.copy(in, out, IoUtil.DEFAULT_BUFFER_SIZE, contentLength, streamProgress); - } catch (final IORuntimeException e) { - //noinspection StatementWithEmptyBody - if (isIgnoreEOFError - && (e.getCause() instanceof EOFException || StrUtil.containsIgnoreCase(e.getMessage(), "Premature EOF"))) { - // 忽略读取HTTP流中的EOF错误 - } else { - throw e; - } - } - return copyLength; - } // endregion ---------------------------------------------------------------------------- Private Methods } diff --git a/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient4/HttpClient4Response.java b/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient4/HttpClient4Response.java index 562ed9be6..cea125b19 100755 --- a/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient4/HttpClient4Response.java +++ b/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient4/HttpClient4Response.java @@ -8,7 +8,6 @@ import cn.hutool.http.client.Response; import org.apache.http.Header; import org.apache.http.ParseException; import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.entity.ContentType; import org.apache.http.util.EntityUtils; import java.io.IOException; @@ -67,8 +66,7 @@ public class HttpClient4Response implements Response { @Override public Charset charset() { - final Charset charset = ContentType.parse(rawRes.getEntity().getContentType().getValue()).getCharset(); - return ObjUtil.defaultIfNull(charset, requestCharset); + return ObjUtil.defaultIfNull(Response.super.charset(), requestCharset); } @Override diff --git a/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient5/HttpClient5Response.java b/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient5/HttpClient5Response.java index d9cffc62f..3b48847f0 100755 --- a/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient5/HttpClient5Response.java +++ b/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient5/HttpClient5Response.java @@ -6,7 +6,6 @@ import cn.hutool.core.util.ObjUtil; import cn.hutool.http.HttpException; import cn.hutool.http.client.Response; import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; -import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.ParseException; import org.apache.hc.core5.http.io.entity.EntityUtils; @@ -67,8 +66,7 @@ public class HttpClient5Response implements Response { @Override public Charset charset() { - final Charset charset = ContentType.parse(rawRes.getEntity().getContentType()).getCharset(); - return ObjUtil.defaultIfNull(charset, requestCharset); + return ObjUtil.defaultIfNull(Response.super.charset(), requestCharset); } @Override diff --git a/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpConnection.java b/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpConnection.java index 956837980..6d4072780 100644 --- a/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpConnection.java +++ b/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpConnection.java @@ -5,7 +5,6 @@ import cn.hutool.core.reflect.FieldUtil; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ObjUtil; import cn.hutool.http.HttpException; -import cn.hutool.http.HttpUtil; import cn.hutool.http.client.HeaderOperation; import cn.hutool.http.meta.Method; import cn.hutool.http.ssl.DefaultSSLInfo; @@ -20,8 +19,6 @@ import java.net.HttpURLConnection; import java.net.ProtocolException; import java.net.Proxy; import java.net.URL; -import java.nio.charset.Charset; -import java.nio.charset.UnsupportedCharsetException; import java.util.List; import java.util.Map; @@ -403,38 +400,6 @@ public class HttpConnection implements HeaderOperation { return 0; } - /** - * 获得字符集编码
- * 从Http连接的头信息中获得字符集
- * 从ContentType中获取 - * - * @return 字符集编码 - */ - public String getCharsetName() { - return HttpUtil.getCharset(conn); - } - - /** - * 获取字符集编码
- * 从Http连接的头信息中获得字符集
- * 从ContentType中获取 - * - * @return {@link Charset}编码 - * @since 3.0.9 - */ - public Charset getCharset() { - Charset charset = null; - final String charsetName = getCharsetName(); - if (StrUtil.isNotBlank(charsetName)) { - try { - charset = Charset.forName(charsetName); - } catch (final UnsupportedCharsetException e) { - // ignore - } - } - return charset; - } - @Override public String toString() { final StringBuilder sb = StrUtil.builder(); diff --git a/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpRequest.java b/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpRequest.java index feb0ac0c2..d3500251d 100755 --- a/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpRequest.java +++ b/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpRequest.java @@ -50,6 +50,7 @@ import java.util.function.Function; * * @author Looly */ +@Deprecated public class HttpRequest extends HttpBase { // ---------------------------------------------------------------- static Http Method start diff --git a/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpResponse.java b/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpResponse.java index c27da6469..5240a651a 100755 --- a/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpResponse.java +++ b/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpResponse.java @@ -1,22 +1,24 @@ package cn.hutool.http.client.engine.jdk; -import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; -import cn.hutool.core.io.stream.FastByteArrayOutputStream; +import cn.hutool.core.io.stream.EmptyInputStream; import cn.hutool.core.text.StrUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjUtil; import cn.hutool.http.HttpException; import cn.hutool.http.client.Response; import cn.hutool.http.client.body.ResponseBody; import cn.hutool.http.client.cookie.GlobalCookieManager; -import java.io.ByteArrayInputStream; import java.io.Closeable; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.HttpCookie; import java.nio.charset.Charset; +import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Map.Entry; /** @@ -25,55 +27,48 @@ import java.util.Map.Entry; * * @author Looly */ -public class HttpResponse extends HttpBase implements Response, Closeable { +public class HttpResponse implements Response, Closeable { + + /** + * 请求时的默认编码 + */ + private final Charset requestCharset; + /** + * 响应内容体,{@code null} 表示无内容 + */ + private ResponseBody body; + private Map> headers; /** * 是否忽略响应读取时可能的EOF异常。
* 在Http协议中,对于Transfer-Encoding: Chunked在正常情况下末尾会写入一个Length为0的的chunk标识完整结束。
* 如果服务端未遵循这个规范或响应没有正常结束,会报EOF异常,此选项用于是否忽略这个异常。 */ - protected boolean ignoreEOFError; + private final boolean ignoreEOFError; + /** * 持有连接对象 */ protected HttpConnection httpConnection; - /** - * Http请求原始流 - */ - protected InputStream in; - /** - * 是否异步,异步下只持有流,否则将在初始化时直接读取body内容 - */ - private volatile boolean isAsync; /** * 响应状态码 */ protected int status; - /** - * 是否忽略读取Http响应体 - */ - private final boolean ignoreBody; - /** - * 从响应中获取的编码 - */ - private Charset charsetFromResponse; /** * 构造 * * @param httpConnection {@link HttpConnection} * @param ignoreEOFError 是否忽略响应读取时可能的EOF异常 - * @param charset 编码,从请求编码中获取默认编码 + * @param requestCharset 编码,从请求编码中获取默认编码 * @param isAsync 是否异步 * @param isIgnoreBody 是否忽略读取响应体 */ - protected HttpResponse(final HttpConnection httpConnection, final boolean ignoreEOFError, final Charset charset, final boolean isAsync, final boolean isIgnoreBody) { + protected HttpResponse(final HttpConnection httpConnection, final boolean ignoreEOFError, final Charset requestCharset, final boolean isAsync, final boolean isIgnoreBody) { this.httpConnection = httpConnection; this.ignoreEOFError = ignoreEOFError; - this.charset = charset; - this.isAsync = isAsync; - this.ignoreBody = isIgnoreBody; - initWithDisconnect(); + this.requestCharset = requestCharset; + init(isAsync, isIgnoreBody); } /** @@ -86,6 +81,29 @@ public class HttpResponse extends HttpBase implements Response, Cl return this.status; } + @Override + public String header(final String name) { + final List headerValues = this.headers.get(name); + if (ArrayUtil.isNotEmpty(headerValues)) { + return headerValues.get(0); + } + return null; + } + + /** + * 获取headers + * + * @return Headers Map + */ + public Map> headers() { + return Collections.unmodifiableMap(headers); + } + + @Override + public Charset charset() { + return ObjUtil.defaultIfNull(Response.super.charset(), requestCharset); + } + /** * 同步
* 如果为异步状态,则暂时不读取服务器中响应的内容,而是持有Http链接的{@link InputStream}。
@@ -94,7 +112,11 @@ public class HttpResponse extends HttpBase implements Response, Cl * @return this */ public HttpResponse sync() { - return this.isAsync ? forceSync() : this; + if (null != this.body) { + this.body.sync(); + } + close(); + return this; } // ---------------------------------------------------------------- Http Response Header start @@ -153,15 +175,13 @@ public class HttpResponse extends HttpBase implements Response, Cl */ @Override public InputStream bodyStream() { - if (isAsync) { - return this.in; - } - return new ByteArrayInputStream(this.bodyBytes); + // 使用ResponseBody中的stream有利于控制响应数据的同步与否 + return null == this.body ? EmptyInputStream.INSTANCE : this.body.getStream(); } @Override public ResponseBody body() { - return new ResponseBody(this, this.ignoreEOFError); + return this.body; } /** @@ -174,30 +194,14 @@ public class HttpResponse extends HttpBase implements Response, Cl @Override public byte[] bodyBytes() { sync(); - return this.bodyBytes; - } - - /** - * 设置主体字节码,一般用于拦截器修改响应内容
- * 需在此方法调用前使用charset方法设置编码,否则使用默认编码UTF-8 - * - * @param bodyBytes 主体 - * @return this - */ - @SuppressWarnings("resource") - public HttpResponse body(final byte[] bodyBytes) { - sync(); - if (null != bodyBytes) { - this.bodyBytes = bodyBytes; - } - return this; + return body().getBytes(); } // ---------------------------------------------------------------- Body end @Override public void close() { - IoUtil.close(this.in); - this.in = null; + // 关闭流 + IoUtil.close(this.body); // 关闭连接 this.httpConnection.disconnectQuietly(); } @@ -211,39 +215,13 @@ public class HttpResponse extends HttpBase implements Response, Cl } sb.append("Response Body: ").append(StrUtil.CRLF); - sb.append(" ").append(this.body()).append(StrUtil.CRLF); + sb.append(" ").append(this.bodyStr()).append(StrUtil.CRLF); return sb.toString(); } - @Override - public String header(final String name) { - return super.header(name); - } - // ---------------------------------------------------------------- Private method start - /** - * 初始化Http响应,并在报错时关闭连接。
- * 初始化包括: - * - *
-	 * 1、读取Http状态
-	 * 2、读取头信息
-	 * 3、持有Http流,并不关闭流
-	 * 
- * - * @throws HttpException IO异常 - */ - private void initWithDisconnect() throws HttpException { - try { - init(); - } catch (final HttpException e) { - this.httpConnection.disconnectQuietly(); - throw e; - } - } - /** * 初始化Http响应
* 初始化包括: @@ -257,7 +235,7 @@ public class HttpResponse extends HttpBase implements Response, Cl * @throws HttpException IO异常 */ @SuppressWarnings("resource") - private void init() throws HttpException { + private void init(final boolean isAsync, final boolean isIgnoreBody) throws HttpException { // 获取响应状态码 try { this.status = httpConnection.getCode(); @@ -276,73 +254,13 @@ public class HttpResponse extends HttpBase implements Response, Cl // StaticLog.warn(e, e.getMessage()); } - // 存储服务端设置的Cookie信息 GlobalCookieManager.store(httpConnection, this.headers); - // 获取响应编码,如果非空,替换用户定义的编码 - final Charset charsetFromResponse = httpConnection.getCharset(); - if (null != charsetFromResponse) { - this.charset = charsetFromResponse; - } - // 获取响应内容流 - this.in = new HttpInputStream(this); - - // 同步情况下强制同步 - if (!this.isAsync) { - forceSync(); + if (false == isIgnoreBody) { + this.body = new ResponseBody(this, new HttpInputStream(this), isAsync, this.ignoreEOFError); } } - - /** - * 强制同步,用于初始化
- * 强制同步后变化如下: - * - *
-	 * 1、读取body内容到内存
-	 * 2、异步状态设为false(变为同步状态)
-	 * 3、关闭Http流
-	 * 4、断开与服务器连接
-	 * 
- * - * @return this - */ - private HttpResponse forceSync() { - // 非同步状态转为同步状态 - try { - this.readBody(this.in); - } catch (final IORuntimeException e) { - //noinspection StatementWithEmptyBody - if (e.getCause() instanceof FileNotFoundException) { - // 服务器无返回内容,忽略之 - } else { - throw new HttpException(e); - } - } finally { - if (this.isAsync) { - this.isAsync = false; - } - this.close(); - } - return this; - } - - /** - * 读取主体,忽略EOFException异常 - * - * @param in 输入流 - * @throws IORuntimeException IO异常 - */ - private void readBody(final InputStream in) throws IORuntimeException { - if (ignoreBody) { - return; - } - - final long contentLength = contentLength(); - final FastByteArrayOutputStream out = new FastByteArrayOutputStream((int) contentLength); - body().writeClose(out); - this.bodyBytes = out.toByteArray(); - } // ---------------------------------------------------------------- Private method end } diff --git a/hutool-http/src/main/java/cn/hutool/http/client/engine/okhttp/OkHttpResponse.java b/hutool-http/src/main/java/cn/hutool/http/client/engine/okhttp/OkHttpResponse.java index 228dcd7ab..5e1808f85 100755 --- a/hutool-http/src/main/java/cn/hutool/http/client/engine/okhttp/OkHttpResponse.java +++ b/hutool-http/src/main/java/cn/hutool/http/client/engine/okhttp/OkHttpResponse.java @@ -1,11 +1,8 @@ package cn.hutool.http.client.engine.okhttp; import cn.hutool.core.io.stream.EmptyInputStream; -import cn.hutool.core.text.StrUtil; -import cn.hutool.core.util.CharsetUtil; -import cn.hutool.http.HttpUtil; +import cn.hutool.core.util.ObjUtil; import cn.hutool.http.client.Response; -import cn.hutool.http.meta.Header; import okhttp3.ResponseBody; import java.io.IOException; @@ -46,12 +43,7 @@ public class OkHttpResponse implements Response { @Override public Charset charset() { - final String contentType = rawRes.header(Header.CONTENT_TYPE.getValue()); - if(StrUtil.isNotEmpty(contentType)){ - final String charset = HttpUtil.getCharset(contentType); - CharsetUtil.parse(charset, this.requestCharset); - } - return this.requestCharset; + return ObjUtil.defaultIfNull(Response.super.charset(), requestCharset); } @Override diff --git a/hutool-http/src/main/java/cn/hutool/http/server/HttpServerRequest.java b/hutool-http/src/main/java/cn/hutool/http/server/HttpServerRequest.java index 4f17a9557..9cec2c3d9 100644 --- a/hutool-http/src/main/java/cn/hutool/http/server/HttpServerRequest.java +++ b/hutool-http/src/main/java/cn/hutool/http/server/HttpServerRequest.java @@ -11,6 +11,7 @@ import cn.hutool.core.net.multipart.UploadSetting; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.ObjUtil; import cn.hutool.http.meta.Header; import cn.hutool.http.HttpUtil; import cn.hutool.http.meta.Method; @@ -169,8 +170,7 @@ public class HttpServerRequest extends HttpServerBase { public Charset getCharset() { if(null == this.charsetCache){ final String contentType = getContentType(); - final String charsetStr = HttpUtil.getCharset(contentType); - this.charsetCache = CharsetUtil.parse(charsetStr, DEFAULT_CHARSET); + this.charsetCache = ObjUtil.defaultIfNull(HttpUtil.getCharset(contentType), DEFAULT_CHARSET); } return this.charsetCache; diff --git a/hutool-http/src/test/java/cn/hutool/http/MockServerTest.java b/hutool-http/src/test/java/cn/hutool/http/MockServerTest.java new file mode 100755 index 000000000..a419b6567 --- /dev/null +++ b/hutool-http/src/test/java/cn/hutool/http/MockServerTest.java @@ -0,0 +1,16 @@ +package cn.hutool.http; + +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +import java.io.IOException; + +public class MockServerTest { + public static void main(final String[] args) throws IOException { + //noinspection resource + final MockWebServer server = new MockWebServer(); + final MockResponse mockResponse = new MockResponse().setBody("hello, world!"); + server.enqueue(mockResponse); + server.start(8080); + } +} diff --git a/hutool-http/src/test/java/cn/hutool/http/client/JdkEngineTest.java b/hutool-http/src/test/java/cn/hutool/http/client/JdkEngineTest.java new file mode 100755 index 000000000..0e69f5155 --- /dev/null +++ b/hutool-http/src/test/java/cn/hutool/http/client/JdkEngineTest.java @@ -0,0 +1,22 @@ +package cn.hutool.http.client; + +import cn.hutool.core.lang.Console; +import cn.hutool.http.client.engine.jdk.JdkClientEngine; +import cn.hutool.http.meta.Method; +import org.junit.Ignore; +import org.junit.Test; + +public class JdkEngineTest { + + @Test + @Ignore + public void getTest(){ + final ClientEngine engine = new JdkClientEngine(); + + final Request req = Request.of("https://www.hutool.cn/").method(Method.GET); + final Response res = engine.send(req); + + Console.log(res.getStatus()); + Console.log(res.bodyStr()); + } +}