Как отключить автоматическое добавление Charset в Content-Type в охттп
Рассмотрим следующий код:
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.
- Если я удалю кодировку из [A], она все равно будет добавлена.
- Если я добавлю кодировку к подписанному URL-адресу до его подписи, он сработает, и GCS вернет 200 OK.
Но это не так, как должно быть. По крайней мере, при работе с подписанными URL-адресами они должны быть отправлены на сервер точно так, как объявлено.
Я попытался использовать HTTP-клиент Apache (который я не хочу использовать в производственном процессе, так как 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 в теле избыточно?
3 ответа
Я нашел решение:
Следующая строка является виновником:
RequestBody body = RequestBody.create(mediaType, media);
create имеет 3 подписи для медиа:
- строка
- байт[]
- файл
Когда я передаю String, он игнорирует предоставленный mediaType и добавляет к нему кодировку. Даже для изображения / JPEG было бы отправить
изображение / JPEG; кодировка = UTF-8
на сервер.
Использование byte[] или File подавляет такое поведение.
Я надеюсь, это поможет вам!
[Глупый я - для простоты я дал ему String во время тестирования, так как я не заботился о теле;-( ]
Когда вы создаете тело запроса, просто установите для типа содержимого значение «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)
}
Вы можете зарегистрироватьnetworkInterceptor
который переопределяет заголовок Content-Type, например:FixContentTypeInterceptor.java:
import okhttp3.*;
import java.io.IOException;
public final class FixContentTypeInterceptor implements Interceptor {
@Override public Response intercept(Interceptor.Chain chain) throws IOException {
Request originalRequest = chain.request();
Request fixedRequest = originalRequest.newBuilder()
.header("Content-Type", "application/json")
.build();
return chain.proceed(fixedRequest);
}
}
Главный.java:
[...]
MediaType JSON = MediaType.get("application/json; charset=utf-8");
String json = "{}";
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new FixContentTypeInterceptor())
.build();
RequestBody body = RequestBody.create(json, JSON);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
[...]
Обсуждается это на Github okhttp. https://github.com/square/okhttp/issues/3081