我正在使用SDK(以前称为 Jetpack)为Firefox开发附加组件。
在我的插件中,我需要通过JSONP请求访问远程服务器(由我控制)上的 PHP 脚本的一些数据,然后使用从服务器返回的数据来更新某些网页元素。
在我的 main.js 文件中,我使用 page-mod 和contentScriptFile将 JQuery 库的副本和我自己的 javascript 文件注入到网页中。我的 javascript 文件使用 JQuery 的“$.ajax”函数来访问远程 PHP 脚本。
问题:从未收到响应。
我偶然发现了这个 StackOverflow 问题,它处理同样的问题: jsonp 调用中的错误 ONLY FROM firefox-extension
我已经遵循了那里的一些建议,并通过指定我自己的回调更改了我的 $.ajax 请求,并使用“unsafeWindow.callback”将回调函数添加到我的文件中——我不完全理解发生了什么,但似乎JQuery 获取的“窗口”引用与真正的底层窗口对象不同(我认为这种事情是由 XRayWrapper 隐形处理的,所以对此感到困惑)。
没关系。我得到一个传递给我的回调的参数(我已将参数标记为“数据”),其中包含整个服务器响应 - 我需要的一切。
问题是,当我之前使用成功时:在 .ajax 函数中,“this”指的是 ajax 对象(我认为 - Javascript 初学者),然后是我想用响应数据更新的页面元素。我无法在自定义回调中访问“this”。
我发现即使我总是从服务器得到响应,并且我的回调触发,JQuery 报告一个错误 - 如果我指定error:,那么这将触发。如果我添加一个完整的:,这也会触发,但是success:永远不会触发。
我认为我可以使用 :complete 代替我的自定义回调,但似乎在调用错误处理代码时,它会清除服务器响应 - 我无法完整访问它:(XHR 对象 .responseText 属性在处理完成时是“未定义的”:)。
因此,我对所有这一切的拼凑解决方案如下。我有我的自定义回调,它传递了完整的服务器响应。我将它存储在一个全局变量中。我指定完成:-接下来(或以后)触发-然后从那里访问全局变量,但也可以通过“this”访问我想更新的页面元素。
这让我很担心,因为可能会快速连续发出几个 AJAX 请求,所以我的解决方案取决于响应处理没有“交错” - 换句话说,我在做一个假设(我不知道这是真的)当 JQuery 接收到响应时,它将在开始处理下一个接收到的响应之前触发该响应的所有事件处理程序。如果不是这样,那么我存储在全局变量中的数据可能与我想成功使用它的页面元素不对应:。到目前为止,它似乎在测试中有效,但可能只是我很幸运。
(旁注:我也使用 QTip2,它是 AJAX 插件 - 也总是抛出错误,而不是无声的。但我发现我可以通过添加错误来抑制它:并设置 xhr.status = 0 - 我会在下面发布一个片段)。
但这似乎是一种可怕而混乱的做事方式。我不明白为什么 JQuery 认为成功接收到服务器响应时出现错误。而且它的错误处理会破坏这个响应非常不方便,这意味着我无法成功处理它:。
有没有人有更整洁的解决方案?在此先感谢您-要遵循的片段(顺便说一下,这些问题仅在我在插件中执行所有这些操作时才存在。如果我在独立页面/脚本中执行相同的操作,则它会执行而不会引发错误,并且完全符合预期)。
unsafeWindow.callback = function(data)
{
MyGlobalServerResponseVariable = data;
}
$.ajax(
{
url: 'http://nottherealurl.com/',
type: 'GET',
data: params,
async: true,
cache: false,
contentType: "text/json; charset=utf-8",
dataType: 'jsonp',
crossDomain: true,
jsonpCallback: "callback",
complete: function(xhr, textStatus)
{
var data = MyGlobalServerResponseVariable;
this.PageElementIWantToUpdate.attr("title", data.somevalue);
...
}
...
}
QTip2 错误抑制:
error: function(xhr, status, error)
{
xhr.status = 0;
}
最后一点,与上述没有直接关系 - 当我在 Firefox 中执行“文件->打开文件”并选择一个网页时,我的插件没有执行。这是设计使然吗?