使用 Jsonp 进行 $.ajax 调用后无法在 Jquery 中检索数据

Posted

技术标签:

【中文标题】使用 Jsonp 进行 $.ajax 调用后无法在 Jquery 中检索数据【英文标题】:cannot retrieve data in Jquery after makin $.ajax call using Jsonp 【发布时间】:2012-05-09 15:59:37 【问题描述】:

我有一个函数用于从我的 RESTFUL WCF 服务中检索数据。返回的数据必须是 JSON。

在客户端,我有一个名为 autosuggest 的 javascript 函数,如下所示:

function autosuggest(location)

var uri= 'http://localhost:2043/Suggest.svc/GetAirportsjson?location='+location;
$.ajax(
        url:uri,
        dataType: 'jsonp',
        jsonp: 'callback',
        jsonpCallback: 'jsonpCallback(e)',
        success: function(e)
            alert("success");
        
    ); ;

Service 接口为:

[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "/GetAirportsXML?location=location")]
    [OperationContract]
    List<Suggestions> GetAirportDataXml(string location);

    [WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "/GetAirportsJSON?location=location")]
    [OperationContract]
    List<Suggestions> GetAirportDataJson(string location);

并且在 Firebug 中观察到 location=m 的响应是

["AirportCode":"MMZ","AirportName":"Maimana","AreaCode":"701","CountryCode":"AF","CountryName":"Afghanistan","AirportCode":"MZR","AirportName":"Mazar-i-sharif","AreaCode":"701","CountryCode":"AF","CountryName":"Afghanistan","AirportCode":"IMZ","AirportName":"Nimroz","AreaCode":"701","CountryCode":"AF","CountryName":"Afghanistan","AirportCode":"TMR","AirportName":"Aguemar","AreaCode":"500","CountryCode":"DZ","CountryName":"Algeria","AirportCode":"BMW","AirportName":"Bordj Badji Mokhtar","AreaCode":"500","CountryCode":"DZ","CountryName":"Algeria","AirportCode":"IAM","AirportName":"In Amenas","AreaCode":"500","CountryCode":"DZ","CountryName":"Algeria","AirportCode":"MUW","AirportName":"Mascara-Ghriss","AreaCode":"500","CountryCode":"DZ","CountryName":"Algeria","AirportCode":"MZW","AirportName":"Mechria","AreaCode":"500","CountryCode":"DZ","CountryName":"Algeria","AirportCode":"MQV","AirportName":"Mostaganem","AreaCode":"500","CountryCode":"DZ","CountryName":"Algeria","AirportCode":"HME","AirportName":"Oued Irara Apt","AreaCode":"500","CountryCode":"DZ","CountryName":"Algeria","AirportCode":"TMX","AirportName":"Timimoun","AreaCode":"500","CountryCode":"DZ","CountryName":"Algeria","AirportCode":"TLM","AirportName":"Zenata","AreaCode":"500","CountryCode":"DZ","CountryName":"Algeria"]

我还将提供我的服务代码

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.ServiceModel.Activation;

namespace AutosuggestAPI.svc

    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class Suggest : IService1
    
        public string GetDateTime()
        
            return DateTime.Now.ToString();
        


        private static List<Suggestions> GetDistinct(List<Suggestions> suggestions)
        
            var length = suggestions.Count;
            var Arr = new Suggestions[length];
            suggestions.CopyTo(Arr);

            var dist = new HashSet<string>();

            foreach (var suggestion in Arr)
            
                if (!dist.Contains(suggestion.AirportCode.ToString()))
                    dist.Add(suggestion.AirportCode.ToString());
                else
                
                    suggestions.Remove(suggestion);
                
            
            return suggestions;
        

        public List<Suggestions> GetAirportDataXml(string location)
        
            var suggestions = new List<Suggestions>();
            var val = string.Empty;
            for (int i = 0; i < 2; i++)
            
                val = i == 0 ? "AirPortName" : "AirPortCode";
                SqlConnection conn = null;
                try
                
                    // create and open a connection object
                    conn = new SqlConnection("Server=(local);DataBase=DBAirPortCodes;Integrated Security=SSPI");
                    conn.Open();

                    // 1. create a command object identifying
                    // the stored procedure
                    var cmd = new SqlCommand("sp_CheckCondition", conn)  CommandType = CommandType.StoredProcedure ;

                    // 2. set the command object so it knows
                    // to execute a stored procedure

                    // 3. add parameter to command, which
                    // will be passed to the stored procedure
                    cmd.Parameters.Add(new SqlParameter("@lookup", val));
                    cmd.Parameters.Add(new SqlParameter("@searchfor", location));
                    var reader = cmd.ExecuteReader();
                    while (reader.Read())
                    
                        var suggestion = new Suggestions()
                        
                            _airportCode = Convert.ToString(reader["AirPortCode"]).Trim(),
                            _airportName = Convert.ToString(reader["AirPortName"]).Trim(),
                            _areaCode = Convert.ToString(reader["AreaCode"]).Trim(),
                            _countryCode = Convert.ToString(reader["CountryCode"]).Trim(),
                            _countryName = Convert.ToString(reader["CountryName"]).Trim()
                        ;
                        suggestions.Add(suggestion);
                    
                
                finally
                
                    if (conn != null)
                        conn.Close();
                
            
            var distinctList = GetDistinct(suggestions);
            return distinctList;
        

        List<Suggestions> GetAirportDataJson(string location)
        
            List<Suggestions> suggestions = GetAirportDataXml(location);

            return suggestions;
        


        public List<Suggestions> GetAirportDataJsonp(string location)
        
            return GetAirportDataXml(location);
        

        public List<Suggestions> GetAllSuggestions()
        
            var suggestions = new List<Suggestions>();
            var val = string.Empty;
            for (int i = 0; i < 2; i++)
            
                val = i == 0 ? "AirPortName" : "AirPortCode";
                SqlConnection conn = null;
                try
                
                    // create and open a connection object
                    conn = new SqlConnection("Server=(local);DataBase=DBAirPortCodes;Integrated Security=SSPI");
                    conn.Open();

                    var cmd = new SqlCommand("sp_GetAllAirports", conn)  CommandType = CommandType.StoredProcedure ;

                    var reader = cmd.ExecuteReader();
                    while (reader.Read())
                    
                        var suggestion = new Suggestions()
                        
                            _airportCode = Convert.ToString(reader["AirPortCode"]).Trim(),
                            _airportName = Convert.ToString(reader["AirPortName"]).Trim(),
                            _areaCode = Convert.ToString(reader["AreaCode"]).Trim(),
                            _countryCode = Convert.ToString(reader["CountryCode"]).Trim(),
                            _countryName = Convert.ToString(reader["CountryName"]).Trim()
                        ;
                        suggestions.Add(suggestion);
                    
                
                finally
                
                    if (conn != null)
                        conn.Close();
                
            
            var distinctList = GetDistinct(suggestions);
            return distinctList;
        

    

问题是调用成功,我在浏览器中获取了数据,但我无法在 Jquery 或 Javascript 中捕获它。 有人可以帮忙吗?

【问题讨论】:

尝试将 console.log(e) 添加到你的成功函数中,看看你是否真的得到了什么,或者只是一个错误。我认为您在预期 jsonp 时返回 json。 我希望它是 json 但服务不在同一个域中。因此使用 jsonp.Also 成功函数根本没有被命中。添加 console.log(e) 后没有任何记录 很有可能问题出在返回的数据上。并且要使用跨域 jsonp,您使用的 REST 服务必须支持它,并返回有效的 jsonp,而不是 json,因为那将不起作用。您可以在服务器端执行此操作,因为这非常简单,或者您可以使用 Yahoo 的 YQL 之类的服务将数据转换为 jsonp。然而,最好的选择可能是让 REST 服务支持 jsonp,如果您可以访问它。 @adeneo:提供了服务代码,您现在能告诉我具体需要如何更改我的服务吗? 【参考方案1】:

您将错误的字符串传递给 jsonCallback。

应该是

function autosuggest(location)

    var uri= 'http://localhost:2043/Suggest.svc/GetAirportsjson?location='+location;
    $.ajax(
        url:uri,
        dataType: 'jsonp',
        jsonpCallback: 'jsonpCallback',
        success: function(e)
            alert("success");
        
    );
 ;

为什么还要用默认值覆盖默认回调参数名称?

已编辑:似乎您并不真正了解 jquery 如何处理 jsonp 内容。

jquery 创建一个函数来处理 jsonp 请求的返回,该请求将 json 作为包含在此函数调用中的纯文本返回。你可以不提供任何功能,这对于 jquery 和更严格的来说更可取

看看following example

你需要提供的参数只有jsonp的数据类型

var r = $.ajax(
    url : uri
    , dataType:'jsonp'
    , success: function (e)    
        viewModel.tweets(e.results);                
    );

编辑 2:您的服务应处理“回调”参数,如果提供,则将响应 json 包装在提供的函数调用中

请求:http://......../GetAirportsjson?location=....&amp;callback=mycallback

回复:mycallback( .... you real json response goes here .... )

在你有这个之前你没有做正确的 jsonp 响应

【讨论】:

我需要覆盖默认回调,以便我可以访问返回的数据并根据我的应用程序进行更改 试过但没用。仍然无法获取数据。并注意到从未调用过 jsonpCallback。 您在 e 中的成功处理程序中拥有什么 您可以通过使用变量“e”以成功的方式访问jsondata。能不能给个jsonpCallback方法分析一下?? @poineer - 使用 jsonp 和 twitter api 调用查看更新的答案以及链接到实时示例

以上是关于使用 Jsonp 进行 $.ajax 调用后无法在 Jquery 中检索数据的主要内容,如果未能解决你的问题,请参考以下文章

AJAX 调用在公司防火墙后失败

jsonp回调函数没有被调用

使用 JSONP 或 CORS 的跨域 JavaScript 调用

带有 jsonp 内容类型的 jQuery.ajax 请求后的解析器错误

如何在 jsonp ajax 调用中使用类型:“POST”

使用 JQuery Ajax 和 JSONP 调用 OData 服务