简而言之
为什么和如何在Spring中覆盖Header中的ContentType?
Spring有一个默认的配置,基于三种策略来选择返回的内容类型。这个配置可以被修改。
自定义所有控制器响应的content-type header
有两种方式可以自定义所有响应的content-type header协商配置,一种是通过XML配置,另一种是通过注解驱动配置。
自定义某些URL的content-type header值
在相同的配置中,有一种方法可以注入一个定制的策略来选择哪些URL受到更改content-type header的规则影响。
在Spring Boot上
幸运的是,在Spring Boot上添加produce属性到控制器的@RequestMapping注解中并更改属性即可获得所需的行为:
- @RequestMapping(value = "/live/timeshift.m3u8", method = RequestMethod.GET, produces = "application/vnd.apple.mpegurl")
- Property - > spring.http.encoding.enabled设置为true
详细回答
为什么和如何在Spring中覆盖Header中的ContentType?
在Spring MVC中,有三个选项来确定请求的媒体类型:
- 请求中的URL后缀(扩展名)(如.xml/.json)
- 请求中的URL参数(如?format=json)
- 您控制器方法所做的接受头部
按照这个顺序,Spring协商content-type header响应和body响应格式,如果没有启用任何一个,则可以指定回退到默认内容类型。
自定义所有控制器响应的content-type header
因此,要自定义此行为,我们应提供回退的默认内容类型并禁用上述三种策略。有两种方法可以实现它,使用XML配置或注解配置:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureContentNegotiation(final ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false).
favorParameter(false).
ignoreAcceptHeader(true).
useJaf(false).
defaultContentType("application/vnd.apple.mpegurl");
}
}
或者XML配置
<bean id="contentNegotiationManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false" />
<property name="favorParameter" value="false"/>
<property name="ignoreAcceptHeader" value="true" />
<property name="defaultContentType" value="application/vnd.apple.mpegurl"/>
<property name="useJaf" value="false" />
</bean>
自定义某些URL的内容类型标头值
另一个定制化的解决方案是创建自己的@DefaultContentType注解。覆盖RequestMappingHandlerMapping#getCustomMethodCondition方法,该方法检查方法上是否有注解@DefaultContentType。自定义条件将始终匹配,但在compareTo中,它将优先考虑具有注解的方法而非没有注解的方法。
如果需要多次使用,则可以执行上述解决方案。
对于一次性事件,可以通过ContentNegotiationConfigurer插入自定义defaultContentTypeStrategy,该策略检查特定URL并返回首选媒体类型,例如:
public class MyCustomContentNegotiationStrategy implements ContentNegotiationStrategy {
@Override
public List<MediaType> resolveMediaTypes (final NativeWebRequest nativeWebRequest)
throws HttpMediaTypeNotAcceptableException {
final List<MediaType> mediaTypes = new ArrayList<>();
final String url =((ServletWebRequest)request).getRequest().getRequestURI().toString();
final String yourUrlpatternString = ".*http://.*";
final Pattern yourUrlPattern = Pattern.compile(patternString);
final Matcher matcher = pattern.matcher(url);
if(matcher.matches()) {
mediaTypes.add("application/vnd.apple.mpegurl");
return mediaTypes;
}
}
然后,通过配置添加您的自定义策略:
@EnableWebMvc
@Configuration
public class MyWebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureContentNegotiation (ContentNegotiationConfigurer configurer) {
configurer.defaultContentTypeStrategy(new MyCustomContentNegotiationStrategy());
}
}
关于Spring Boot
最后,如果你正在使用Spring Boot,就像@StavShamir建议的那样,在回答https://dev59.com/Qbvoa4cB1Zd3GeqP76mm#62422889中,有一堆常见的应用程序属性可能对这种情况有帮助:
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=
spring.http.encoding.force-request= specified.
spring.http.encoding.force-response=
spring.http.encoding.mapping=
在这种情况下,将
spring.http.encoding.enabled 属性设置为true并使用@ RequestMapping注释中的参数将起作用: https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#common-application-properties
@RequestMapping(value = "/live/timeshift.m3u8", method = RequestMethod.GET, produces = "application/vnd.apple.mpegurl")
setVaryResponseHeader
方法。 - Stav Shamir