2013-10-09 41 views
0

我正在嘗試編寫一個小工具,用於顯示api.openweathermap.org當前的溫度。 小工具通過setTimeout「循環」中的異步XMLHttpRequest獲取信息(因此天氣數據每隔幾分鐘更新一次),但有時XHR的responseText未定義,這當然會引發錯誤並停止循環,並且不可避免地會導致更新過程。來自側邊欄小工具中XHR的未定義responseText

提琴手顯示流量熄滅,響應返回有效和預期的數據,但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. 我已經使用了不同的Web服務 - 雅虎天氣和小工具完美無缺地工作。雅虎返回XML,OpenWeatherApi - JSON。我還不知道它是否與我的問題有關,因爲正如我之前所說 - OWA有時可以工作。

  2. CORS絕對不是小工具的問題。 This小提琴檢索不到數據,並在檢查我可以看到一條消息,指出

    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. 
    

    然而,在我的小工具,數據是沒有問題的檢索。

回答

0

這很可能是由於在瀏覽器中實現的跨域安全策略(跨源資源共享 - 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

+0

我相信同源策略不是在小工具的環境執行。爲了支持我的說法 - 小工具首先起作用,對於前三個「updateWeather()」調用,可以訪問「responseText」字段。然後它不是,這是什麼讓我撓了腦袋。 – Konrad

+0

嗯好吧,聽起來和瀏覽器中的CORS發生的問題完全一樣,在檢查網絡流量時沒有錯誤,並且響應正確,但javascript無法訪問它。我不熟悉構建Windows小工具,但我認爲他們在某種無鉻瀏覽器中運行?我想檢查Fiddler中的標題信息可能會有所幫助。 – heardy