diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/client/body/HttpBody.java b/hutool-http/src/main/java/org/dromara/hutool/http/client/body/HttpBody.java index ab323b4b8..071e6e60d 100644 --- a/hutool-http/src/main/java/org/dromara/hutool/http/client/body/HttpBody.java +++ b/hutool-http/src/main/java/org/dromara/hutool/http/client/body/HttpBody.java @@ -14,6 +14,7 @@ package org.dromara.hutool.http.client.body; import org.dromara.hutool.core.io.stream.FastByteArrayOutputStream; import org.dromara.hutool.core.io.IoUtil; +import org.dromara.hutool.core.text.StrUtil; import java.io.InputStream; import java.io.OutputStream; @@ -32,23 +33,39 @@ public interface HttpBody { void write(OutputStream out); /** - * 获取Content-Type + * 获取Content-Type
+ * 根据实现不同,Content-Type可能包含编码信息,也可以不包含 * * @return Content-Type值 */ String getContentType(); /** - * 获取指定编码的Content-Type,类似于:application/json;charset=UTF-8 + * 获取指定编码的Content-Type,类似于:application/json;charset=UTF-8
+ * 如果{@link #getContentType()} 已经包含编码信息,则编码信息一致直接返回,否则替换为指定编码。 + * * @param charset 编码 * @return Content-Type + * @see #getContentType() */ - default String getContentType(final Charset charset){ - final String contentType = getContentType(); - if(null == contentType){ + default String getContentType(final Charset charset) { + String contentType = getContentType(); + if (null == contentType) { return null; } + final String charsetName = charset.name(); + if (StrUtil.endWithIgnoreCase(contentType, charsetName) || StrUtil.containsIgnoreCase(contentType, "boundary=")) { + // 已经包含编码信息,且编码一致,无需再次添加 + // multipart无需添加charset + return contentType; + } + + if (StrUtil.containsIgnoreCase(contentType, ";charset=")) { + // 已经包含编码信息,但编码不一致,需要替换 + contentType = StrUtil.subBefore(contentType, ";charset=", true); + } + return contentType + ";charset=" + charset.name(); } diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/client/body/MultipartBody.java b/hutool-http/src/main/java/org/dromara/hutool/http/client/body/MultipartBody.java index c1bbbd0ca..dae5d1e70 100644 --- a/hutool-http/src/main/java/org/dromara/hutool/http/client/body/MultipartBody.java +++ b/hutool-http/src/main/java/org/dromara/hutool/http/client/body/MultipartBody.java @@ -84,6 +84,12 @@ public class MultipartBody extends FormBody { return CONTENT_TYPE_MULTIPART_PREFIX + boundary; } + @Override + public String getContentType(final Charset charset) { + // multipart的Content-Type头指定"Content-Type; boundary=XXXX",编码无效 + return getContentType(); + } + /** * 写出Multiparty数据,不关闭流 * diff --git a/hutool-http/src/test/java/org/dromara/hutool/http/client/Issue3658Test.java b/hutool-http/src/test/java/org/dromara/hutool/http/client/Issue3658Test.java new file mode 100644 index 000000000..b0ae3a34f --- /dev/null +++ b/hutool-http/src/test/java/org/dromara/hutool/http/client/Issue3658Test.java @@ -0,0 +1,24 @@ +package org.dromara.hutool.http.client; + +import org.dromara.hutool.core.collection.CollUtil; +import org.dromara.hutool.http.meta.HeaderName; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Collection; +import java.util.Collections; + +public class Issue3658Test { + + @Test + public void name() { + // 请注意这里一定使用带form参数的get方法,参数随便设什么都行,url也随便 + final Request request = Request.of("https://timor.tech/api/holiday/year/2020-02") + .form(Collections.singletonMap("11", "22")); + + final Collection collection = request.headers().get(HeaderName.CONTENT_TYPE.getValue()); + final String s = CollUtil.get(collection, 0); + Assertions.assertEquals("application/x-www-form-urlencoded;charset=UTF-8", s); + } + +}