Retrofit拦截器中使用addHeader()无法生成正确请求的问题
Retrofit全局拦截器设置Content-Type不生效问题排查与解决
问题背景
尝试通过OkHttp的HeaderInterceptor全局添加Content-Type: application/json请求头,但测试发现不生效;在Retrofit接口方法上使用@Headers("Content-Type: application/json")注解则能正常请求服务器。排查后确认核心原因:
- 拦截器方式发送请求时,最终传递的请求头为
application/json; charset=UTF-8,服务器无法识别该格式 @Headers注解方式会保留原始指定的Header值,不会被自动追加编码后缀
问题根源
Retrofit的GsonConverterFactory在序列化请求体时,会自动为Content-Type追加; charset=UTF-8后缀。使用应用拦截器时,拦截器的执行顺序在Converter处理之前,所以拦截器设置的纯application/json会被Converter修改;而@Headers注解的Header会被Retrofit直接使用,不会被Converter修改。
解决方法
方法一:改用OkHttp网络拦截器
网络拦截器在请求体被Converter处理之后、实际发送给服务器之前执行,可直接覆盖被修改后的Content-Type:
// 修改OkHttpClient构建逻辑,使用addNetworkInterceptor private val client = OkHttpClient.Builder() .addNetworkInterceptor(HeaderInterceptor()) .build() class HeaderInterceptor : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request() .newBuilder() .header("Content-Type", "application/json") // 用header()覆盖原有值 .build() return chain.proceed(request) } }
方法二:自定义GsonConverterFactory,禁用自动追加charset
如果不想修改拦截器类型,可自定义Converter,避免自动添加编码后缀:
// 自定义ConverterFactory class CustomGsonConverterFactory private constructor(private val gson: Gson) : Converter.Factory() { companion object { fun create(gson: Gson = Gson()): CustomGsonConverterFactory { return CustomGsonConverterFactory(gson) } } override fun requestBodyConverter( type: Type, parameterAnnotations: Array<Annotation>, methodAnnotations: Array<Annotation>, retrofit: Retrofit ): Converter<*, RequestBody>? { val adapter = gson.getAdapter(TypeToken.get(type)) return CustomGsonRequestBodyConverter(gson, adapter) } } // 自定义RequestBodyConverter class CustomGsonRequestBodyConverter<T>( private val gson: Gson, private val adapter: TypeAdapter<T> ) : Converter<T, RequestBody> { private val MEDIA_TYPE = MediaType.parse("application/json") override fun convert(value: T): RequestBody { val buffer = Buffer() val writer = OutputStreamWriter(buffer.outputStream(), Charset.forName("UTF-8")) val jsonWriter = gson.newJsonWriter(writer) adapter.write(jsonWriter, value) jsonWriter.close() return RequestBody.create(MEDIA_TYPE, buffer.readByteString()) } }
然后替换Retrofit中的ConverterFactory:
fun getRetrofit(): Retrofit{ return Retrofit.Builder() .baseUrl(BASE_URL) .client(client) .addConverterFactory(CustomGsonConverterFactory.create()) // 使用自定义Converter .build() }
注意事项
- 使用
header()方法而非addHeader(),确保覆盖所有已存在的Content-Type头,避免出现多个重复Header的情况 - 两种方法都能确保最终发送给服务器的
Content-Type为纯application/json,适配服务器的识别要求
内容的提问来源于stack exchange,提问作者Álvaro
相关产品推荐
相关产品推荐

