Issue with JSONP



作为学习JSONP的一部分,我正在进行如下ajax调用:

var jsonp_url = "http://localhost:8080/test/ad";
$.getJSON(jsonp_url, function(data) {
   $('#example-widget-container').html(data.html);
});

当我点击http://localhost:8080/test/ad时,它返回:

? ( {'html': '<strong>Hello World!</strong>' } )

返回这个的Spring代码是:

@RequestMapping(method = RequestMethod.GET, value = "ad")
public void getAd(HttpServletResponse response){
    PrintWriter out = null;
    response.setContentType("text/javascript");
    try {
        out = response.getWriter();
    } catch (IOException e) {
        e.printStackTrace();
    }
    out.write("? ( {'html': '<strong>Hello World!</strong>' } )");
}

在执行时,我期待Hello World!应该在<div id="example-widget-container"></div>中显示,但它没有,因为回调没有发生。

我错过了什么?

$。getJSON除了正确的JSON格式和callme({'html': 'hello world'})不是JSON格式

正确的json格式是{'html': 'hello world'}

你不只是想要return "{'html': 'hello world' }";吗?

如果你返回JSON,不要得到JSON…试试这个

$.get("http://localhost:8080/test/ad", function(data) {
   alert(data.html);
}, 'jsonp');

callme函数在做什么?如果你返回"callme({'html': 'hello world'})";那么在你的js代码警报将不会警报"hello world"。你需要有data(),即运行callme函数

我发现很多人对JSONP和JSON感到困惑。所以我分享了我发现的正确答案:

Java

@RequestMapping(method = RequestMethod.GET, value = "ad")
public void getAd(HttpServletRequest request, HttpServletResponse response){
   ServletOutputStream out;
   try {
      out = response.getOutputStream();
      response.setContentType("text/javascript; charset=utf-8");
      out.println(request.getParameter("callback")+" ( {'html': '<strong>Hello World!</strong>' } )");
      out.close();
   } catch (IOException e) {
      e.printStackTrace();
   }
}
Javascript

var jsonp_url = "http://localhost:8080/AppName/ad?callback=?";
$.getJSON(jsonp_url, function(data) {
   $('#example-widget-container').html(data.html);
});

使用Spring 3.0及以上版本实际上非常容易。然而,在查看上面的示例时,我很困惑,为什么您将spring控制器视为普通servlet并直接打印到响应流。这是应该避免的。如果只返回一个表示JSON数组的POJO,并让JSON解析器创建响应,效果会好得多。

第一个任务是让Spring返回JSON。这很容易通过在控制器中添加@ResponseBody来处理,告诉控制器将POJO序列化到客户端。如果你在你的类路径中有Jackson,它将自动作为JSON发送,使用MappingJacksonHttpMessageConverter,它是用mvc:annotation-driven启用的。

但是JSON是不够的。您需要JSON- p,假设客户端希望在跨域场景中使用JSON。这可以通过许多不同的方式实现。您可以使用Spring的DelegatingFilterProxy实现servlet过滤器。过滤器可以确定是否正在请求JSON-P,您可以相应地调整响应。

所以对于我的使用,我更喜欢扩展Spring 3.0 (+) MappingJacksonJsonView而不是过滤器,并检查请求参数是否包含一个键"callback"。如果我想要JSON或JSONP,我可以简单地添加第二个servlet映射到*。并根据回调参数的存在发送JSON或jsonp。

代码如下:

在控制器中输入以下内容:

@RequestMapping(value="/ad", method=RequestMethod.GET)
public ModelMap getAvailabilityModel(@RequestParam(required = false) String callback) {
    ModelMap modelMap = new ModelMap();
    modelMap.addAttribute("html", "<strong>Hello World!</strong>");
    return modelMap;
}   

返回一个ModelMap或甚至一个ModelAndView允许我基于servlet映射做不同的事情。

下面是处理JSON-P扩展的自定义视图(仅限内部,为简洁起见省略了一些覆盖):

public class MappingJacksonJsonpView extends MappingJacksonJsonView {
@Override 
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
if("GET".equals(request.getMethod().toUpperCase())) {
    Map<String, String[]> params = request.getParameterMap();
    if(params.containsKey("callback")) {
    String callbackName = params.get("callback")[0];
    response.getOutputStream().write(new String(callbackName + "(").getBytes());
    log.info("GETTER Found for a .jsonp method, callback name is : " + callbackName);
    super.render(model, request, response);
    response.getOutputStream().write(new String(");").getBytes());
    response.setContentType("application/javascript");
    }
    else {
    super.render(model, request, response);
    }
}
else {
    super.render(model, request, response);
}
  }
 }

如果请求被映射到*。我看到一个带有"callback"作为键的请求参数,我假设是JSON- p,并将JSON与回调信息包装在响应流的顶部。我将让Jackson JSON处理器处理在所有情况下将POJO转换为适当JSON的细节。在我的控制器中,我只是返回POJO或ModelMap;无需在响应中编写自己的JSON。另外,我也可以使用模型和视图作为返回类型。这将允许正确处理*。做* * *。json请求。使用Firebug确保您在响应头中获得正确的媒体类型,application/json为json, application/javascript为json - p。

下面是JSON-P的输出,在http://localhost:8080/jsonpex/ad.jsonp?callback=xyz上有一个GET(注意到带有xyz的包装器,用于JQuery吗?)

xyz({"html":"<strong>Hello World!</strong>"});

如果不使用Request参数,它将返回JSON: http://localhost:8080/jsonpex/ad.jsonp

{"html":"<strong>Hello World!</strong>"}

最后,确保正确地连接了新视图:

<!-- Add our new View to the Application Context -->
<beans:bean  class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <beans:property name="order" value="1" />
    <beans:property name="favorPathExtension" value="true"/>
    <beans:property name="mediaTypes">
        <beans:map>
            <beans:entry key="json" value="application/json"/>
            <beans:entry key="jsonp" value="application/javascript"/>
        </beans:map>
    </beans:property>
    <beans:property name="defaultViews">
        <beans:list>
            <beans:bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/>
            <beans:bean class="com.yourpackagename.spring.web.servlet.view.jsonp.MappingJacksonJsonpView"/>
        </beans:list>
    </beans:property>
</beans:bean>

需要注意的是,我会避免返回所有额外的HTML,并尽可能地减少,将工作的关键放在返回的数据上。我做了很多研究,尝试了很多方法;上面这个最适合我。我建议以下作为替代方案和额外阅读,因为它们是导致我找到这个最终解决方案的原因(遗憾的是,我不能全部记住,否则我会给予更多的信任):

http://blog.springsource.com/2010/01/25/ajax-simplifications-in-spring-3-0/

,对于过滤器解决方案:

http://jpgmr.wordpress.com/2010/07/28/tutorial-implementing-a-servlet-filter-for-jsonp-callback-with-springs-delegatingfilterproxy/

旅行

最新更新