JSONP问题

时间:2011-10-12 11:20:20

标签: jquery json spring 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>中,但不是,因为回调没有发生。

我错过了什么?

6 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

如果您要返回JSONP,请不要获取JSON ...试试这个

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

答案 3 :(得分:0)

callme函数在做什么?如果你要返回“callme({'html':'hello world'})”;然后在你的js代码警报中不会提醒“Hellow world”。你需要有data(),即运行callme函数

答案 4 :(得分:0)

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

爪哇

@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);
});

答案 5 :(得分:0)

使用Spring 3.0及更高版本实际上非常简单。在查看上面的示例时,我很困惑为什么要将spring控制器视为普通servlet并直接打印到响应流。这应该避免。只使用返回表示JSON数组的POJO并让JSON解析器创建响应,你会好得多。

第一个任务是让Spring返回JSON。通过将@ResponseBody添加到控制器可以轻松处理,告诉控制器将POJO序列化到客户端。如果您的类路径中有Jackson,则会使用使用mvc:annotation-driven启用的MappingJacksonHttpMessageConverter自动将其作为JSON发送。

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

因此,对于我的用途,我更喜欢扩展Spring 3.0(+)MappingJacksonJsonView而不是过滤器,并检查请求参数是否包含“回调”键。如果我想要JSON或JSONP,我可以简单地向* .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扩展的自定义视图(仅限guts,为简洁起见省略了一些覆盖):

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);
}
  }
 }

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

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

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

如果您取消请求参数,它将只返回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/

旅行