接氣象局 API、跨網域 AJAX 資料

/

本篇要解決的問題

最近遇到了一個需求,就是要能夠在進入頁面時,看到天氣的預報。

查了一下,氣象局的文件說明得很簡單,就是 GET 的 URL 上填 token 跟要的資料 id 就行,一些 Google 到的教學文也都是類似方式。

可是這些教學文沒說的是,GET 來的資料,不會是從氣象局的 Domain 來的,一定是要跨網域請求,因此就會在 Console 看到以下畫面:

傳說中的 No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
傳說中的 No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

本篇想解決的問題,就是如何能處理跨網域 AJAX,真正的取得氣象局 API 來的資料。


接氣象局 API 需要的 3 個東西

  1. 氣象局提供的授權碼
  2. 取得要 AJAX 的 URL
  3. 可跨網域取得資料的 API

1 氣象局提供的授權碼

進到氣象局的「開發指南」頁面後,會看到以下畫面:

氣象局開發指南頁面,未登入會員
氣象局開發指南頁面,未登入會員

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

氣象局開發指南頁面,登入會員後
氣象局開發指南頁面,登入會員後

按下去就可以取得授權碼了,這授權碼先存起來,之後 AJAX 的 URL 會用到。

2 取得要 AJAX 的 URL

要取得 URL,氣象局有提供生成器:中央氣象局開放資料平臺之資料擷取 API

比方想要取台北市天氣的預報資料,就點選「鄉鎮天氣預報-臺北市未來 2 天天氣預報」,會看到以下:

這是廣告,點擊一下可以幫本站多個一點點的廣告收入,謝謝

鄉鎮天氣預報-臺北市未來2天天氣預報
鄉鎮天氣預報-臺北市未來 2 天天氣預報

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

氣象局api的input生成url
氣象局 API 的 input 生成 URL

填完、選完這些項目後,再按下底部的「Execute」,就會產生結果預覽跟要 AJAX 的 URL:

按下底部的「Execute」
按下底部的「Execute」
最後產生的request URL
最後產生的 Request URL

拿 Request URL 去 GET,就可以取得所要的資料。

補充:只想取得某個區的資料

地區直接用台北市的話,就會回傳整個台北市的天氣資料,但如果只想要某個區呢?比方說信義區?

只要在填寫時,loactionName 那邊填寫要的區就行了,如圖:

locationName填寫只要get的區
locationName 填寫只要 GET 的區

這樣回傳的值就只會有信義區的資料。

想跨網域取得氣象局的資料,前 2 樣有了,最後一項就是建一個可以跨網域取得資料的 API,以下開始筆記自己的撞牆之旅XD~


跨網域 AJAX 資料

要取得跨網域的資料,Google 了很多種方法,比較常見的是 JSONP,但用 JS 試了又試,就是一直看到 Console 報錯,因為跨網域問題所以資料進不來。

這邊提供 2 種方法:

這是廣告,點擊一下可以幫本站多個一點點的廣告收入,謝謝

  1. 直接用別人寫好的線上功能
  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 掛掉多久,你 AJAX 出來的頁面也會壞多久。

如果是自己開發,又是純前端,還無法自己建一個後端的 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

Summary
接氣象局 API、跨網域 AJAX 資料
Article Name
接氣象局 API、跨網域 AJAX 資料
Description
本篇大綱:本篇要解決的問題、接氣象局api需要的3個東西 -1 氣象局提供的授權碼 -2 取得要get的url -3 可跨網域取得資料的api -4 補充:只想取得某個區的資料。跨網域get資料 -1 直接用別人寫好的線上功能 -2 自己寫一個後端api,用api去取資料
Augustus
Let's Write
Let's Write
https://letswrite.tw/wp-content/uploads/2020/08/logo_512.jpg

隨選筆記文

API

Instagram Embedding 抓 iframe 高度及 3 種大小圖片

API

Imgur API:upload, load 上傳、讀取 心得筆記

Vue

用 Vue CLI 3 + Vuetify 製作說明頁面

Apps Script Google

Google Apps Script 讀寫 Cloud Firestore 資料

WordPress

WordPress:埋 Google AdSense 廣告

Google Maps

Google Maps API 學習筆記 – 4:Place API 自動完成地址、地點評論摘要

Front-End

不會寫程式,也能自己架一個免費網站:Publii + GitHub Pages

Vue

用 VuePress 製作說明文件頁面 – 4:佈景主題、外掛

WordPress

Ubuntu 安裝 WordPress – 1:VirtualBox、Ubuntu 20.04

PWA

PWA 學習筆記 – 4:manifest.json

以下是留言,但關於留言的部份必需先讓你們知道:

本站的文章都是 August 因為覺得有趣,才會實作並整理成筆記文而後進行發表。

如果留言是希望把 Demo 改成「你想要」的樣子,或是把功能改成「符合你需求」的樣子,

Sorry~ 除非那修改是 August 也有興趣的,不然不會幫你們寫程式去面對工作或是交作業。

未來這類的留言不會再主動回覆。😎

另外,公開信箱是為了讓金流驗證用,

因為之前遇過幾次回信協助解決問題後,對方卻一聲謝謝也沒有,就這樣拿去幫工作交差。

因此決定不再回覆信件,有疑問就利用留言功能囉。