[英]How to suppress Charset being automatically added to Content-Type in okhttp
Consider the following code:考虑以下代码:
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();
I am accessing GCS from a client, with a previously signed URL.我从客户端访问 GCS,使用先前签名的 URL。
Problem: It seems okhttp adds the charset declared for the body [A] to the URL as well (at least for text/plain), even though it is not declared in [B].问题:似乎 okhttp 还将为正文 [A] 声明的字符集添加到 URL(至少对于文本/纯文本),即使它没有在 [B] 中声明。 This messes up my signed URL and GCS returns 403 Forbidden.
这弄乱了我的签名 URL,GCS 返回 403 Forbidden。
But this is not as it should be.但这不是它应该的样子。 At least when working with signed URLs, these must be sent to the server exactly as declared.
至少在使用签名 URL 时,这些必须完全按照声明发送到服务器。
I tried using the Apache http client (which I don't want to use in production as okhttpclient is already part of my installation) and that client does not expose this behavior:我尝试使用 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();
Is there a way to suppress the behavior in okhttp, that it adds to the Content-Type or transfers the Content-Type within the body redundantly?有没有办法抑制 okhttp 中的行为,它添加到 Content-Type 或在正文中多余地传输 Content-Type?
I found the solution:我找到了解决方案:
The following line is the culprit:以下行是罪魁祸首:
RequestBody body = RequestBody.create(mediaType, media);
create has 3 signatures for media: create 有 3 个媒体签名:
When I pass a String, it disregards the supplied mediaType and adds the charset to it.当我传递一个字符串时,它会忽略提供的 mediaType 并将字符集添加到其中。 Even for image/jpeg it would send
即使对于图像/jpeg,它也会发送
image/jpeg;图像/jpeg; charset=utf-8
字符集=utf-8
to the server.到服务器。
Using byte[] or File suppresses that behavior.使用 byte[] 或 File 会抑制这种行为。
I hope this helps you!我希望这可以帮助你!
[Stupid me - for simplicity I gave it a String during testing, as I didn't care about the body ;-( ] [愚蠢的我 - 为简单起见,我在测试期间给了它一个字符串,因为我不关心身体;-(]
When you create requestbody, just set the content typy as "null", and add header manual, like this:创建请求体时,只需将内容类型设置为“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();
Beacuse when I read okhttp source code, in RequestBody.kt, I find following code:因为当我阅读 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.