【问题标题】:Undefined responseText from XHR in sidebar gadget侧边栏小工具中来自 XHR 的未定义 responseText
【发布时间】:2013-10-09 23:08:47
【问题描述】:

我正在尝试编写一个显示来自 api.openweathermap.org 的当前温度的小工具。 该小工具通过 setTimeout“循环”中的异步 XMLHttpRequest 提取信息(因此天气数据每隔几分钟更新一次),但有时 XHR 的 responseText 未定义,这当然会引发错误并停止循环,并且不可避免地会导致更新过程。

Fiddler 显示流量消失,响应返回一个有效且预期的数据,但 XHR 无法以某种方式访问​​它。

相关的JS位:

var timer;      // these three 
var locStr;     // are defined 
var weather;    // elsewhere

function showWeather()
{
    System.Debug.outputString('showWeather()');
    if (timer) clearTimeout(timer);
    locStr = System.Gadget.Settings.readString("location");

    // this is for first-run use only - when the setting is not set, display an appropriate notification to the user
    if (locStr == "")
    {
        cell.style.display = 'none';
        welcome.style.display = 'block';
    }
    else
    {
        cell.style.display = 'block';
        welcome.style.display = 'none';

        updateWeather();
    }
}

function updateWeather()
{
    System.Debug.outputString('updateWeather()');
    try
    {
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function()
        {
            System.Debug.outputString('updateWeather()>onreadystatechange ' + xhr.status + ' ' + xhr.readyState);
            if (xhr.status === 200)
            {
                if (xhr.readyState === 4)
                {
                    // this is what makes it fail:
                    System.Debug.outputString(xhr.responseText);
                    weather = eval('(' + xhr.responseText + ')'); // i DO get that eval is evil, but works for my purposes well.

                    // temp, city, wind and clouds are html entities id values
                    temp.innerHTML = Math.round(weather.main.temp) + '<span>&deg;C</span>';
                    city.innerHTML = weather.name;
                    wind.innerHTML = weather.wind.speed + ' m/s';
                    clouds.innerHTML = weather.clouds.all + '%';

                    // clears and hides error, if occured in previous fetch
                    error_title.innerHTML = '';
                    error_description.innerHTML = '';
                    error.style.display = 'none';

                    timer = setTimeout(updateWeather, 1000 * 5);
                }
                else
                {
                    temp.innerText += '.';
                }
            }
            else
            {
                error_title.innerText = 'Connectivity error';
                error_description.innerText = xhr.status + '.'; // that's really informative...
                error.style.display = 'block';

                timer = setTimeout(updateWeather, 5000)
            }
        };
        xhr.ontimeout = function()
        {
            error_title.innerText = 'Connectivity error';
            error_description.innerText = 'timed out';
            error.style.display = 'block';

            timer = setTimeout(updateWeather, 5000);
        };
        xhr.open('get', 'http://api.openweathermap.org/data/2.5/weather?q=' + locStr + '&units=metric&dummy=' + Math.ceil(100*Math.random()), false);
        xhr.setRequestHeader('Cache-Control', 'no-cache');
        xhr.send();
    }
    catch (e)
    {
        error_title.innerText = e.name;
        error_description.innerText = e.message;
        error.style.display = 'block';

        timer = setTimeout(updateWeather, 5000);
    }
}

showWeather() 在窗口的 onload 事件中被调用,然后检查用户是否在首选项中设置了位置(城市)并在 updateWeather() 中启动循环。

updateWeather() 然后发出请求并适当地处理数据,这是可行的,但只要我不尝试访问 responseText。

我对这个问题束手无策,但我觉得我在这里缺少一些基本的东西,而且我对 JS 还不是很有经验。

我想在这里使用纯 javascript,我没有花哨的库。

请指教。

更新

我做了一些更改和测试,结果如下:

  1. 我使用了不同的网络服务 - Yahoo!天气和小工具完美无缺。雅虎返回 XML、OpenWeatherApi - JSON。我还不知道这是否与我的问题有关,因为正如我之前所说 - OWA 有时会起作用。

  2. CORS 绝对不是小工具的问题。 This fiddle 无法检索数据,在检查器中我可以看到一条消息说明

    XMLHttpRequest cannot load http://weather.yahooapis.com/forecastrss?w=526363&u=c.
    No 'Access-Control-Allow-Origin' header is present on the requested resource.
    Origin 'http://fiddle.jshell.net' is therefore not allowed access.
    

    但在我的小工具中,数据检索没有问题。

【问题讨论】:

    标签: javascript xmlhttprequest windows-desktop-gadgets


    【解决方案1】:

    这很可能是由于浏览器中实现的跨域安全策略(Cross Origin Resource Sharing – CORS、W3C)机制造成的。通过 javascript 对来自不同域的资源的 HTTP 请求将失败(如果服务器支持,您可以使用 JSONP 解决此问题)。要启用 CORS,您尝试连接的服务器需要将您的域添加到“Access-Control-Allow-Origin”HTTP 标头或允许所有域(使用星号通配符“*”表示)。

    MDN 文章供参考 - https://developer.mozilla.org/en/docs/HTTP/Access_control_CORS

    有人已经记录了这个问题:http://bugs.openweathermap.org/issues/152

    【讨论】:

    • 我相信在小工具环境中不会强制执行同源策略。为了支持我的说法 - 小工具首先工作,对于前三个左右的 updateWeather() 调用,responseText 字段是可访问的。然后它就不是了,这让我摸不着头脑。
    • 嗯,好吧,听起来和浏览器中的 CORS 出现的问题完全一样,没有错误,并且在检查网络流量时响应是正确的,但 javascript 无法访问它。我不熟悉构建 Windows 小工具,但我认为它们在某种无铬浏览器中运行?我想检查 Fiddler 中的标头信息可能会有所帮助。
    猜你喜欢
    • 2010-09-20
    • 2010-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多