[英]How to suppress Charset being automatically added to Content-Type in okhttp
考虑以下代码:
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("text/plain; charset=utf-8"); // [A]
RequestBody body = RequestBody.create(mediaType, media);
String[] aclHeader = "x-goog-acl:public-read".split(":");
Request request = new Request.Builder()
.addHeader("Content-Type", "text/plain") // [B]
.addHeader(aclHeader[0], aclHeader[1])
.url(url)
.put(body)
.build();
Response response = client.newCall(request).execute();
我从客户端访问 GCS,使用先前签名的 URL。
问题:似乎 okhttp 还将为正文 [A] 声明的字符集添加到 URL(至少对于文本/纯文本),即使它没有在 [B] 中声明。 这弄乱了我的签名 URL,GCS 返回 403 Forbidden。
但这不是它应该的样子。 至少在使用签名 URL 时,这些必须完全按照声明发送到服务器。
我尝试使用 Apache http 客户端(我不想在生产中使用它,因为 okhttpclient 已经是我安装的一部分)并且该客户端没有公开这种行为:
String[] aclHeader = "x-goog-acl:public-read".split(":");
StatusLine statusLine = Request
.Put(url)
.addHeader("Content-Type", "text/plain")
.addHeader(aclHeader[0], aclHeader[1])
.bodyByteArray(media)
.execute().returnResponse().getStatusLine();
有没有办法抑制 okhttp 中的行为,它添加到 Content-Type 或在正文中多余地传输 Content-Type?
我找到了解决方案:
以下行是罪魁祸首:
RequestBody body = RequestBody.create(mediaType, media);
create 有 3 个媒体签名:
当我传递一个字符串时,它会忽略提供的 mediaType 并将字符集添加到其中。 即使对于图像/jpeg,它也会发送
图像/jpeg; 字符集=utf-8
到服务器。
使用 byte[] 或 File 会抑制这种行为。
我希望这可以帮助你!
[愚蠢的我 - 为简单起见,我在测试期间给了它一个字符串,因为我不关心身体;-(]
创建请求体时,只需将内容类型设置为“null”,并添加标题手册,如下所示:
OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create('your media string', null);
String[] aclHeader = "x-goog-acl:public-read".split(":");
Request request = new Request.Builder()
.addHeader("Content-Type", "text/plain") // [B]
.addHeader(aclHeader[0], aclHeader[1])
.url(url)
.put(body)
.build();
Response response = client.newCall(request).execute();
因为当我阅读 okhttp 源代码时,在 RequestBody.kt 中,我发现以下代码:
/**
* Returns a new request body that transmits this string. If [contentType] is non-null and lacks
* a charset, this will use UTF-8.
*/
@JvmStatic
@JvmName("create")
fun String.toRequestBody(contentType: MediaType? = null): RequestBody {
var charset: Charset = UTF_8
var finalContentType: MediaType? = contentType
if (contentType != null) {
val resolvedCharset = contentType.charset()
if (resolvedCharset == null) {
charset = UTF_8
finalContentType = "$contentType; charset=utf-8".toMediaTypeOrNull()
} else {
charset = resolvedCharset
}
}
val bytes = toByteArray(charset)
return bytes.toRequestBody(finalContentType, 0, bytes.size)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.