You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中如何修改Feign响应头 将text/plain改为application/json

问题原因

你之前配置的@Headers注解、HeaderTestRequestInterceptor仅作用于发往目标服务的请求,无法修改服务端返回的响应头。默认配置的JacksonDecoder只会识别Content-Type为application/json的响应,遇到响应头为text/plain但实际内容为JSON的返回值时,不会执行JSON反序列化逻辑,因此无法转换为POJO对象。

解决方案

以下两个方案可直接落地,按需选择即可。

方案1:自定义Decoder兼容text/plain类型(兼容性最好,推荐)

无需单独修改响应头,直接扩展JacksonDecoder,让其支持解析text/plain类型的JSON内容,代码如下:

import com.fasterxml.jackson.databind.ObjectMapper;
import feign.FeignException;
import feign.Response;
import feign.jackson.JacksonDecoder;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.regex.Pattern;

public class CustomJacksonDecoder extends JacksonDecoder {
    private static final Pattern TEXT_CONTENT_PATTERN = Pattern.compile("text/.*");

    public CustomJacksonDecoder() {
        super();
    }

    public CustomJacksonDecoder(ObjectMapper objectMapper) {
        super(objectMapper);
    }

    @Override
    public Object decode(Response response, Type type) throws IOException, FeignException {
        // 检测到text类型响应时,替换Content-Type头为application/json后再走原生解析逻辑
        if (response.headers().getOrDefault("Content-Type", Collections.emptyList())
                .stream().anyMatch(contentType -> TEXT_CONTENT_PATTERN.matcher(contentType).matches())) {
            response = response.toBuilder()
                    .replaceHeader("Content-Type", "application/json;charset=UTF-8")
                    .build();
        }
        return super.decode(response, type);
    }
}

替换Feign构建逻辑中的Decoder配置即可生效:

this.feign = Feign.builder()
        .requestInterceptor(new HeaderTestRequestInterceptor())
        .encoder(new JacksonEncoder())
        // 替换为自定义Decoder
        .decoder(new CustomJacksonDecoder())
        .contract(new SpringMvcContract())
        // 注意:这里第一个参数必须替换为你自定义的Feign接口类型
        .target(MozambiqueheApi.class, "https://api.test.re");

方案2:通过响应拦截器统一修改Content-Type头

该方案适用于Feign 11及以上版本,低版本请使用方案1。
如果你需要在解码环节前统一修改所有响应的Content-Type,可以自定义响应拦截器:

import feign.InvocationContext;
import feign.Response;
import feign.ResponseInterceptor;

import java.util.Collections;

public class ContentTypeModifyInterceptor implements ResponseInterceptor {
    @Override
    public Object intercept(InvocationContext context, Chain chain) throws Exception {
        Response response = context.response();
        if (response != null) {
            boolean isTextPlain = response.headers().getOrDefault("Content-Type", Collections.emptyList())
                    .stream().anyMatch(ct -> ct.contains("text/plain"));
            if (isTextPlain) {
                Response modifiedResponse = response.toBuilder()
                        .replaceHeader("Content-Type", "application/json;charset=UTF-8")
                        .build();
                context = context.toBuilder().response(modifiedResponse).build();
            }
        }
        return chain.next(context);
    }
}

构建Feign客户端时注册该拦截器即可:

this.feign = Feign.builder()
        .requestInterceptor(new HeaderTestRequestInterceptor())
        // 注册响应拦截器
        .responseInterceptor(new ContentTypeModifyInterceptor())
        .encoder(new JacksonEncoder())
        .decoder(new JacksonDecoder())
        .contract(new SpringMvcContract())
        .target(MozambiqueheApi.class, "https://api.test.re");
额外注意点
  • 你在Feign接口方法上加的@Headers("Content-Type: application/json")属于冗余配置:GET请求无请求体,不需要指定该请求头,且你已经在请求拦截器中做了同名配置。
  • 原有代码中Feign构建逻辑的.target()方法第一个参数传入Feign.class是错误的,必须传入你自定义的接口类型MozambiqueheApi.class,否则接口方法无法完成映射,调用时会抛出方法不存在的异常。
  • 你当前定义的TestPojo类仅映射了global.name字段,接口返回的uid、level、bans等字段如果需要使用,自行在实体类中补充对应属性和get/set方法即可。

内容的提问来源于stack exchange,提问作者Soul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 12:42:14