本篇大綱
本篇要解決的問題
最近遇到了一個需求,就是要能夠在進入頁面時,看到天氣的預報。
查了一下,氣象局的文件說明得很簡單,就是get的url上填token跟要的資料id就行,一些google到的教學文也都是類似方式。
可是這些教學文沒說的是,get來的資料,不會是從氣象局的domain來的,一定是要跨網域請求,因此就會在console看到以下畫面:

本篇想解決的問題,就是如何能處理跨網域get,真正的取得氣象局api來的資料。
接氣象局api需要的3個東西
- 氣象局提供的授權碼
- 取得要get的url
- 可跨網域取得資料的api
1 氣象局提供的授權碼
進到氣象局的「開發指南」頁面後,會看到以下畫面:

只要註冊成為會員並登入後,就會看到「您的授權碼需登入會員後始可取得」變成「取得授權碼」的按鈕:

按下去就可以取得授權碼了,這授權碼先存起來,之後get的url會用到。
2 取得要get的url
要取得url,氣象局有提供生成器:中央氣象局開放資料平臺之資料擷取API
比方想要取台北市天氣的預報資料,就點選「鄉鎮天氣預報-臺北市未來2天天氣預報」,會看到以下:

點右側的「Try it out」,就會看見下面的說明變成一個個的填充題:

填完、選完這些項目後,再按下底部的「Execute」,就會產生結果預覽跟要get的url:
這是廣告,點擊一下可以幫本站多個一點點的廣告收入,謝謝


拿request URL去get,就可以取得所要的資料。
補充:只想取得某個區的資料
地區直接用台北市的話,就會回傳整個台北市的天氣資料,但如果只想要某個區呢?比方說信義區?
只要在填寫時,loactionName那邊填寫要的區就行了,如圖:

這樣回傳的值就只會有信義區的資料。
想跨網域取得氣象局的資料,前2樣有了,最後一項就是建一個可以跨網域取得資料的api,以下開始筆記自己的撞牆之旅XD~
跨網域get資料
要取得跨網域的資料,google了很多種方法,比較常見的是jsonp,但用js試了又試,就是一直看到console報錯,因為跨網域問題所以資料進不來。
這邊提供2種方法:
- 直接用別人寫好的線上功能
- 自己寫一個後端api,用api去取資料
1 直接用別人寫好的線上功能
這線上功能的名字叫「JSON 2 JSONP」:https://json2jsonp.com/
提供的code是這樣:
這是廣告,點擊一下可以幫本站多個一點點的廣告收入,謝謝
https://json2jsonp.com/?url=http://domain.com/some/json&callback=cbfunc
把url後面的值換成氣象局的request URL,callback的值換成資料進來時要用的function就行了。
用別人寫好的api很快,像JSON 2 JSONP,別人都處理好了,只需要換個url跟function的名稱就行。
缺點就是,這是別人寫的,是用別人的server,如果哪天沒經營就沒了,再如果短時間內server有問題,那server掛掉多久,你get出來的頁面也會壞多久。
如果是自己開發,又是純前端,還無法自己建一個後端的api出來,可以考慮用這套。
但如果懂一點node.js或其他後端語言,就可以選擇自己寫一支api出來。
2 自己寫一個後端api,用api去取資料
如果google一下「ajax cross domain」的話,看到的解答很多都是用php去寫,像這篇:jQuery AJAX cross domain
當然,如果找一個可以用php的主機,把找到的答案ctrl c、ctrl v,然後上傳後也是可以,就是少了自己的消化。
之前學過一點node.js,這次就想用node.js來處理。
一開始寫的code如下:
用express處理http。用request接氣象局資料。因為取資料時有一併發送要抓取的時間區間,所以也裝了body-parser,並從get改成post。
最重要的就是「cross domain config」那段,設定了header後才能跨網域請求。
寫完這段後,把程式佈署上google cloud platform上就可以執行了。
如何把node.js的程式佈到GCP上?請參考這篇:
用Google Cloud Platform(GCP)建node.js網站
原本以為佈上去後,就可以開開心心的從氣象局接資料,但問題來了,假設放在GCP上的程式,產生的網站為A網站,我實際要呈現氣象資料的網站是B網站,從B站去取A站的資料,不也是跨網域嗎?
對,所以當從B網站post出去後,又一樣看到console上寫「No ‘Access-Control-Allow-Origin’ header is present on the requested resource.」
又看到這句,傻眼了。
但好在後端這次是自己處理的,只要把B網站的網域設在白名單裡就行。
google了一下,參考了這篇:POST to express.js with ‘Access-Control-Allow-Origin’
更新了第一版寫的code後如下:
測試過後,真的除了設定的網域可以get、post,其他網域是會被禁止的。
原始碼整理在Github上,歡迎取用:
https://github.com/letswritetw/letswrite-weather-api


和我現在問題一模一樣 謝謝
不客氣喔,另外如果只是單純想跨網域取得氣象局的資料,可以看這篇:
https://letswrite.tw/gas-ajax-firebase/#google-apps-script-ajax
這是用Google Apps Script的服務,有Google帳號就可以在雲端硬碟中建一個檔案,直接在檔案裡就可以寫js了,省去布署到GCP的工。