请求链中多内容类型/Accept头处理问题:代理服务场景下406错误解决方案咨询
嗨,这个问题我之前做微服务代理的时候也碰到过,本质是代理服务的Accept头匹配逻辑和下游服务的版本控制逻辑没对齐导致的,给你几个实用的解决思路:
更新Service A的produces配置,兼容带版本的媒体类型
现在你的Service A的produces只设置了MediaType.APPLICATION_JSON_VALUE(对应application/json),但用户发送的vnd.example+json;version=1属于自定义的带版本标识的媒体类型,Service A会认为没有匹配的返回格式,所以抛出406错误。
解决方法很直接,把produces扩展成包含这些自定义媒体类型的集合:produces = { MediaType.APPLICATION_JSON_VALUE, "application/vnd.example+json;version=1", "application/vnd.example+json;version=2" // 若需要兼容多个版本,可继续添加 }如果想动态兼容所有版本的该类型,还可以用通配符写法:
"application/vnd.example+json;version=*",主流框架比如Spring MVC是支持这种通配符匹配的。在Service A中做Accept头的转发与适配
既然Service A是代理,核心职责是转发请求到下游B-E服务,那可以在拦截器或过滤器里处理Accept头:- 先通过第一步的配置让Service A接受用户发送的带版本的Accept头;
- 把这个头原封不动转发给下游服务,让下游服务处理版本逻辑;
- 如果需要统一处理版本(比如用户请求
version=latest时自动替换为当前最新版本号),还可以在Service A中做头的替换:// 示例:在请求拦截器中修改Accept头 String originalAccept = request.getHeader("Accept"); if (originalAccept != null && originalAccept.contains("version=latest")) { // 假设当前最新版本是v2,替换后转发给下游 String latestVersionAccept = originalAccept.replace("version=latest", "version=2"); request.setHeader("Accept", latestVersionAccept); }
调整Service A的响应媒体类型匹配策略
如果不想修改produces的固定配置,可以通过框架配置放宽媒体类型匹配规则。比如在Spring Boot中,你可以自定义ContentNegotiationConfigurer来让Service A识别vnd.example+json系列的媒体类型:@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { configurer.favorParameter(false) .ignoreAcceptHeader(false) .useRegisteredExtensionsOnly(false) .defaultContentType(MediaType.APPLICATION_JSON) .mediaType("vnd.example+json", MediaType.valueOf("application/vnd.example+json")); } }这样配置后,Service A会把所有带
vnd.example+json的媒体类型都当作合法的JSON类型处理,不会因为附带version参数就拒绝请求。纯代理场景的简化处理
如果Service A只是纯转发请求,本身不生成业务响应,那可以直接把produces设置为*/*(接受所有媒体类型):produces = {MediaType.ALL_VALUE}这种方式最省事,但要注意安全性,确保Service A只转发给可信的下游服务,避免被恶意请求利用。
备注:内容来源于stack exchange,提问作者noob123

