How to suppress Charset being automatically added to Content-Type in okhttp
考虑以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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(); |
我正在使用先前已签名的URL从客户端访问GCS。
问题:似乎okhttp也将为正文[A]声明的字符集也添加到URL中(至少对于文本/纯文本而言),即使未在[B]中声明也是如此。这弄乱了我签名的URL,GCS返回403 Forbidden。
- 如果我从[A]中删除字符集,则仍会添加它。
- 如果在我对字符集进行签名之前将其添加到已签名的URL中,则该字符集将起作用并且GCS返回200 OK。
但这不是应该的。至少在使用签名的URL时,这些URL必须完全按照声明的方式发送到服务器。
我尝试使用Apache http客户端(我不想在生产环境中使用它,因为okhttpclient已经是我的安装的一部分),并且该客户端没有暴露此行为:
1 2 3 4 5 6 7 8 9 10 |
是否有一种方法可以抑制okhttp中的行为,即将其添加到Content-Type或在主体内冗余地传输Content-Type?
我找到了解决方法:
以下是罪魁祸首:
1 | RequestBody body = RequestBody.create(mediaType, media); |
create具有3个媒体签名:
- 细绳
- 字节[]
- 文件
当我传递一个String时,它会忽略提供的mediaType并将字符集添加到其中。即使对于图像/ jpeg,它也会发送
图片/ jpeg;字符集= utf-8
到服务器。
使用byte []或File抑制该行为。
希望这对您有所帮助!
[愚蠢的我-为简单起见,我在测试过程中给了它一个String,因为我并不关心身体;-(]
创建请求正文时,只需将内容类型设置为" null ",然后添加标题手册,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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中找到了以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /** * 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) } |