AngularJS调用第三方接口JSONP无响应,如何获取回调内数据?
问题分析与解决方案
首先咱们得先搞清楚为啥你的$http.jsonp拿不到结果——问题出在后端返回的JSONP格式不符合Angular的预期,而且还有几个小细节没处理对,咱们一步步来解决:
核心问题点
- 回调函数名不匹配:Angular的
$http.jsonp默认会生成一个随机的回调函数名(比如angular.callbacks._0),并通过你指定的callback参数传递给后端,但你的后端硬编码了回调函数名projectInstance.jsonpCallback,完全没接收前端传的回调名。 - 参数格式不符合标准:标准JSONP的回调函数只会接收一个JSON对象参数,但你的后端返回了两个参数:
"getActiveProduct"和目标数据,这也会导致Angular无法解析。 - 代码小疏漏:你调用了
$sce.trustAsResourceUrl(url)但没把返回值赋值给url,相当于白调用了,Angular还是会把这个URL当成不安全资源拦截。
最优解决方案:修改后端为标准JSONP格式
如果能说服后端同事调整返回格式,这是最省心的方案,标准JSONP应该满足两个要求:
- 后端要读取URL中的
callback参数值,把这个值作为回调函数名 - 回调函数只传递一个JSON对象参数,去掉多余的
"getActiveProduct"参数
修改后的后端返回示例:
// 假设前端传的callback参数值是angular.callbacks._0 angular.callbacks._0({"totalRecords":null,"projectSnapShot":[{"projectId":"333333","projectNumber":"123456","projectStatus":"Active"}]})
然后调整你的前端代码:
getActiveProduct: function() { var deferred = $q.defer(); var url = "myserver/getproject.json"; // 关键:把信任后的URL赋值回去 url = $sce.trustAsResourceUrl(url); $http.jsonp(url, { jsonpCallbackParam: 'callback' // 告诉Angular用这个URL参数传递回调名 }).then(function(response){ // response.data就是后端返回的JSON数据 deferred.resolve(response.data); },function(error){ console.log(error); // 这里注意之前的err是笔误,应该是error deferred.reject(error); }); return deferred.promise; }
备选方案:无法修改后端时的手动处理
如果后端完全不能改,那咱们就得绕过Angular的$http.jsonp,手动创建script标签加载资源,并定义对应的全局回调函数来处理非标准响应:
getActiveProduct: function() { var deferred = $q.defer(); var url = "myserver/getproject.json"; url = $sce.trustAsResourceUrl(url); // 先在全局定义后端指定的回调函数 window.projectInstance = window.projectInstance || {}; window.projectInstance.jsonpCallback = function(funcName, data) { // funcName是后端传的"getActiveProduct",data是咱们要的实际数据 deferred.resolve(data); // 加载完成后清理script标签和全局回调,避免污染 document.body.removeChild(scriptTag); delete window.projectInstance.jsonpCallback; }; // 创建script标签加载目标URL var scriptTag = document.createElement('script'); scriptTag.src = url; document.body.appendChild(scriptTag); // 加个超时处理,防止请求挂起 setTimeout(function() { // 检查promise是否还未完成 if (deferred.promise.$$state.status === 0) { deferred.reject(new Error('请求超时')); document.body.removeChild(scriptTag); delete window.projectInstance.jsonpCallback; } }, 5000); // 5秒超时,可根据需求调整 return deferred.promise; }
总结
- 优先选修改后端为标准JSONP,这样能直接用Angular的
$http.jsonp,代码更规范也更容易维护; - 实在改不了后端,就用手动创建script标签的方式,自己处理非标准的回调格式。
内容的提问来源于stack exchange,提问作者user3760261
相关产品推荐
相关产品推荐

