简体   繁体   English

如何抑制字符集被自动添加到 okhttp 中的 Content-Type

[英]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。

  • If I remove the charset from [A], it is still added.如果我从 [A] 中删除字符集,它仍然会被添加。
  • If I add the charset to the signed URL before I sign it, it works and GCS returns 200 OK.如果我在签名之前将字符集添加到签名的 URL 中,它会起作用并且 GCS 返回 200 OK。

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 个媒体签名:

  • String细绳
  • byte[]字节[]
  • File文件

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.

相关问题 okhttp 不允许设置内容类型 - okhttp does not allow for setting of content-type 如何使用“ Content-type:application / x-www-form-urlencoded”发出Okhttp请求? - How to make an Okhttp Request with “Content-type:application/x-www-form-urlencoded”? 如何在IBM HTTPD服务器上设置Content-Type HTTP标头的字符集部分? - How do I set the charset portion of the Content-Type HTTP Header on an IBM HTTPD Server? Java应用程序服务器如何决定在HTTP Content-type标头中发送什么字符集? - How does a Java application server decide what charset to send in the HTTP Content-type header? 如何在 Spring boot(v2.4.2) 中从 Content-Type 响应头中删除 charset=UTF-8 - How to remove charset=UTF-8 from Content-Type response header in Spring boot(v2.4.2) 在 Struts 中使用 HttpServletResponse 时如何从 Content-type 中删除字符集 - How to remove charset from Content-type when using HttpServletResponse in Struts 在 Java 中解析 Content-Type 标头而不验证字符集 - Parsing a Content-Type header in Java without validating the charset 在Content-Type中指定charset时,Jersey和@FormParam无法正常工作 - Jersey and @FormParam not working when charset is specified in the Content-Type 是内容类型“text/xml; 字符集=utf-8”错了吗? - Is content-type “text/xml; charset=utf-8” wrong? 即使不是文本MIME类型,Undertow也会始终向Content-Type标头添加charset - Undertow always add charset to Content-Type header even if it is not a text MIME type
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM