Spring 4:MappingJackson2HttpMessageConverter 不支持 jsonp 的 application/javascript

Posted

技术标签:

【中文标题】Spring 4:MappingJackson2HttpMessageConverter 不支持 jsonp 的 application/javascript【英文标题】:Spring 4: MappingJackson2HttpMessageConverter does not support application/javascript for jsonp 【发布时间】:2015-09-19 03:13:43 【问题描述】:

使用 Spring 4.1.6.RELEASE 和 Jackson 库 v2.5.4

想使用 Spring 4 在我的 REST 服务中使用 JSONP; Spring 4 支持开箱即用的 JSONP。

配置

<mvc:annotation-driven
    content-negotiation-manager="contentNegotiationManager">
...
</mvc:annotation-driven>

按以下方式使用 contentNegotiationManager

<bean id="contentNegotiationManager"
    class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">

    <property name="defaultContentType" value="application/json" />


    <!-- Configuration of Path Extension Based ContentNegotiationStrategy -->
    <property name="favorPathExtension" value="false" />

    <!-- Configuration of Request Parameter Based ContentNegotiationStrategy -->
    <property name="favorParameter" value="true" />
    <property name="parameterName" value="formatType" />
    <property name="mediaTypes" ref="mediaTypesMapping" />
    <!-- Configuration of HTTP ACCEPT Header Based ContentNegotiationStrategy -->
    <property name="ignoreAcceptHeader" value="true" />

</bean>

这里是 MediaTypeMapping

<util:map id="mediaTypesMapping">
    <entry key="json" value="application/json" />
    <entry key="xml" value="application/xml" />
    <entry key="jsonp" value="application/javascript" />
</util:map>

这里是 jsonpParameterNames

<util:set id="jsonpParameterNames">
    <value>param1</value>
    <value>param2</value>
    <value>param3</value>
</util:set>

部署了我的 REST 服务。

点击以下 URL 会得到 json 格式的数据

 /contextRoot/info/1?formatType=json

点击以下 URL 会得到 xml 格式的数据

 /contextRoot/info/1?formatType=xml

点击以下网址会出现 406 异常

 /contextRoot/info/1?formatType=jsonp&param1=callback1

观察

在做调查时,发现 MappingJackson2HttpMessageConverter 不支持应用程序/javascript。

对此感到惊讶,因为 Spring 4 声称支持开箱即用的 JSONP。

此外,MappingJackson2JsonView 确实支持开箱即用的 JSONP。

问题

我是否遗漏了配置中的某些内容,一旦添加后,我就可以通过 SPRING 4 开箱即用地使用内容类型 application/javascript for JSONP?

编辑

这是我的 ControllerAdvice 配置:

<bean id="jsonpAdvice"
    class="com.advice.AccountServiceControllerJsonpAdvice">
    <constructor-arg ref="jsonpParameterNames" />
</bean>

这里是 ControllerAdvice

 public class AccountServiceControllerJsonpAdvice extends
    AbstractJsonpResponseBodyAdvice 

private String[] callbackList = "callback";

public String[] getCallbackList() 
    return callbackList;


public void setCallbackList(String[] callbackList) 
    this.callbackList = callbackList;


public AccountServiceControllerJsonpAdvice(String... callbackList) 
    super(callbackList);


但是,这不会使我的应用程序理解如下 URL 并返回 406 错误

   /contextRoot/info/1?formatType=jsonp&param1=callback1

它只会让我的应用程序理解如下请求 URL 并返回 JSONP 响应:

   /contextRoot/info/1?param1=callback1

【问题讨论】:

【参考方案1】:

是的,Spring 4.1+ 支持 JSONP,但它本身并不是一种转换格式。

MappingJackson2HttpMessageConverter 支持"application/json""*+json" 媒体类型,但不支持"application/javascript"。如果确实如此,那么您会希望它解析 javascript 代码,但事实并非如此

在这里,我们只是将输出包装成"application/javascript",但实际上,它仍然是 JSON。

您当前的配置是禁用与 HTTP Accept 标头的内容协商(为什么?)。为了支持 JSONP,您只需要在 MVC 配置中使用它:

<mvc:annotation-driven/>

还有一个像这样的ControllerAdvice (see reference documentation):

@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice 

    public JsonpAdvice() 
        super("callback");
    

就是这样。

现在你会得到:

GET /contextRoot/info/1
// will return what's best depending on the Accept header sent by the client

GET /contextRoot/info/1.xml
// will return XML

GET /contextRoot/info/1.json
// will return JSON

GET /contextRoot/info/1.json?callback=myFunction
// will return JSONP wrapped in a "myFunction" call

在你的情况下,你应该:

    从您的媒体类型映射中删除"application/javascript",或为了向后兼容将"jsonp""application/json" 媒体类型关联。 使用GET /contextRoot/info/1?formatType=json&amp;param1=callback1

有关实施的更多详细信息,请参阅AbstractJsonpResponseBodyAdvice。

【讨论】:

嗨,Brian,我也在使用 controllerAdvice。但是,它仅在 URL 如下时支持 JSONP:/contextRoot/info/1?param1=callback1 相反,我希望 URL 的格式为:/contextRoot/info/1?formatType=jsonp&param1=callback1; 当我们打算使用 JSONP 格式时,难道我们不是隐含地打算使用 application/javascript 媒体类型吗?甚至 MappingJackson2JsonView 也适用于 application/javascript。那么为什么启用它来处理 Javascript 代码呢? 转换器应该能够读取/写入内容 - Jackson 无法解析 javascript 源代码... MappingJackson2JsonView 也是一个单向过程:写入,而不是读取。 JSONP 只支持 GET 请求,不支持 PUT。所以不能通过 GET 请求发送数据(也不能以 JSONP 格式发送)。那么如何解析应用程序/javascript 或 JSONP 数据呢?是否有可能出现 Request 本身是 JSONP 格式的场景? 让我也向我解释一下这一点的重要性:我们正在迁移到 Spring 4,并且在我们为 JSONP 支持定制实现之前。我们使用的 URL 格式为 ----“contextRoot/info/12?format=jsonp&callback=value”。 ----我们需要在迁移到 Spring 4 时保持 REST URL 的向后兼容性。

以上是关于Spring 4:MappingJackson2HttpMessageConverter 不支持 jsonp 的 application/javascript的主要内容,如果未能解决你的问题,请参考以下文章

Spring 框架 4.0 和 Spring security 3.2.4 上的 Spring Security SAML 扩展

spring笔记

spring笔记

Spring实战(第4版)

Spring 4 安全、MySQL、c3p0 连接。登录在 Spring 5 中有效,但在 Spring 4 中无效

spring framework Annotation(注解)