得益於 Cloudflare 在全球超過 200 多個節點,我們可以很輕易的將我們的應用程式快速的推向 Cloudflare 的全球網路邊緣,這可以讓我們的應用程式的 Response Time 變得更低,如一個以 SPA 技術開發的 Web Application 就可以很輕易的佈署至 Cloudflare Worker。
基礎環境建立
首先我們需要安裝用於佈署 Worker 的工具:@cloudflare/wrangler,我們可以透過 npm 來安裝這個工具:
~$ sudo npm install -g @cloudflare/wrangler
安裝完畢之後我們進入 Cloudflare 的網站,在右欄的部份找到這個區塊,並按下 "取得您的 API Token"。
進入頁面之後點選 API Token 的 Tab 並按下"建立 Token"
並且在建立的頁面中點選 "編輯 Cloudflare Worker",並進入頁面
在權限的區塊,這裡選定的區塊是 "編輯 cloudflare worker 必要的權限",因此若沒有其他的需求,就不用額外調整權限區塊。在帳戶資源部份請至少選擇 "包含" 自己的帳戶。區域資源的部份可以選擇特定區域,以免不小心異動其他網域的內容,如果沒有這類的疑慮,也可以直接選擇包含所有區域。
確定之後就會跳出摘要頁面,確認資料無誤之後就可以按下"建立 Token":
取得上述的 Token 之後我們就可以回到 Terminal,輸入指令後按照要求將 API Token 貼上
~$ wrangler config To find your API Token, go to https://dash.cloudflare.com/profile/api-tokens and create it using the "Edit Cloudflare Workers" template. If you are trying to use your Global API Key instead of an API Token (Not Recommended), run `wrangler config --api-key`. Enter API Token: B4jLkMW933P3P5tsDOqLbKZLi9UMLPEkH8xQdOI7 Validating credentials... Successfully configured. You can find your configuration file at: /home/floatflower/.wrangler/config/default.toml
看到 Successfully configured 之後就代表環境已經設定好囉。
佈署網站
建立一個靜態網頁模板
~$ wrangler generate --site mysite Creating project called `mysite`... Done! New project created /home/floatflower/mysite You will need to update the following fields in the created wrangler.toml file before continuing: You can find your account_id in the right sidebar of your account's Workers page, and zone_id in the right sidebar of a zone's overview tab at https://dash.cloudflare.com - account_id ~$ cd mysite
接著我們就會拿到這些檔案:
. ├── node_modules ├── package-lock.json ├── public │ ├── 404.html │ ├── favicon.ico │ ├── img │ │ ├── 200-wrangler-ferris.gif │ │ └── 404-wrangler-ferris.gif │ └── index.html ├── workers-site │ ├── index.js │ ├── package.json │ └── package-lock.json └── wrangler.toml
- public 資料夾就是放置靜態網站的資料夾,你可以把你的靜態網頁放在裡面。
- worker-site 就是 Cloudflare Worker 的程式碼,你可以在這裡定義自己的 Cloudflare Worker 行為,但是在這裡我們也不用做其他改變,直接用預設的就可以了。
調整 wrangler.toml
我們打開 wrangler.toml 裡面含有這些內容:
# worker 名稱 name = "mysite" type = "webpack" account_id = "" # 如果選擇 true 的話,Cloudflare 會提供給你一個 .workers.dev 網域的網址,因為我們要提供網域,所以我們將其設為 false。 workers_dev = false # 如果 workers_dev 是 false 時,這個 route 一定要提供,我這邊示範的網址是 mysite.fres.host。 route = "mysite.fres.host/*" zone_id = "" [site] bucket = "./public"
其中的 account_id
以及 zone_id
我們就會回到剛才取得 API Token 那個區塊:
其中的區域識別碼貼至 zone_id
以及帳戶識別碼貼至 account_id
。
佈署上線
接著我們執行佈署的指令
~$ wrangler publish ... Built successfully, built project size is 13 KiB. Created namespace for Workers Site "__mysite-workers_sites_assets" Success Uploading site files Deployed to the following routes: mysite.fres.host/* => created
接著我們回到 Cloudflare Worker 的頁面:
就會看到一個 mysite.fres.host/* => mysite
,但是還沒結束。我們要進入 DNS 的頁面,新增一個 DNS Record:
DNS Record 的值可以為隨意,因為全部都會被 Cloudflare 攔截起來,所以網域不管指向哪裡都可以,對應完畢之後我們就可以打開瀏覽器並訪問網址,在這裡我的網址是 https://mysite.fres.host 。
就會看到 Cloudflare 的預設頁面,做到這裡最基本的 Cloudflare 佈署就完成了。
番外篇:用 Cloudflare Worker 佈署 History mode 的 Vue SPA Application
首先我們先開啟一個 Vue SPA 的應用程式,並選擇開啟 History Mode,然後我們將剛才產生的 wrangler.toml 以及 worker-site 移到這個 mysite_spa 底下。
~$ vue create mysite_spa
接著在設定之前首先先看一下 Vue.js 官方文件提到當需要佈署 History mode 的應用程式時,所需要做的設定,以 Nginx 做範例:
location / { try_files $uri $uri/ /index.html; }
概念就是先 try-file 看看有沒有路徑對應的文件,如果沒有則遞送 index.html。
更改 wrangler.toml
因為在 Vue Application 中 public 資料夾另有他用,因此我們不能照常將 wrangler.toml
的 bucket 設為 ./public
資料夾,而是要將其改成 ./dist
。
# 將 site 區塊的設定改成這樣 [site] bucket = "./dist"
更改 worker-site/index.js
接著我們要修改 worker-site/index.js
檔案的內容,以符合上述提到的 Nginx 遞送 Vue Application 的邏輯。
我們先打開 worker-site/index.js
import { getAssetFromKV, mapRequestToAsset } from '@cloudflare/kv-asset-handler' /** * The DEBUG flag will do two things that help during development: * 1. we will skip caching on the edge, which makes it easier to * debug. * 2. we will return an error message on exception in your Response rather * than the default 404.html page. */ const DEBUG = false addEventListener('fetch', event => { try { event.respondWith(handleEvent(event)) } catch (e) { if (DEBUG) { return event.respondWith( new Response(e.message || e.toString(), { status: 500, }), ) } event.respondWith(new Response('Internal Error', { status: 500 })) } }) async function handleEvent(event) { const url = new URL(event.request.url) let options = {} /** * You can add custom logic to how we fetch your assets * by configuring the function `mapRequestToAsset` */ // options.mapRequestToAsset = handlePrefix(/^\/docs/) try { if (DEBUG) { // customize caching options.cacheControl = { bypassCache: true, } } const page = await getAssetFromKV(event, options) // allow headers to be altered const response = new Response(page.body, page) response.headers.set('X-XSS-Protection', '1; mode=block') response.headers.set('X-Content-Type-Options', 'nosniff') response.headers.set('X-Frame-Options', 'DENY') response.headers.set('Referrer-Policy', 'unsafe-url') response.headers.set('Feature-Policy', 'none') return response } catch (e) { // if an error is thrown try to serve the asset at 404.html if (!DEBUG) { try { let notFoundResponse = await getAssetFromKV(event, { mapRequestToAsset: req => new Request(`${new URL(req.url).origin}/404.html`, req), }) return new Response(notFoundResponse.body, { ...notFoundResponse, status: 404 }) } catch (e) {} } return new Response(e.message || e.toString(), { status: 500 }) } } /** * Here's one example of how to modify a request to * remove a specific prefix, in this case `/docs` from * the url. This can be useful if you are deploying to a * route on a zone, or if you only want your static content * to exist at a specific path. */ function handlePrefix(prefix) { return request => { // compute the default (e.g. / -> index.html) let defaultAssetKey = mapRequestToAsset(request) let url = new URL(defaultAssetKey.url) // strip the prefix from the path for lookup url.pathname = url.pathname.replace(prefix, '/') // inherit all other props from the default request return new Request(url.toString(), defaultAssetKey) } }
程式有點長,不過我們並沒有要修改太多,找到以下這個區塊,這個區塊定義了當應用程式找不到指定檔案的時候就返回 404.html 並將 Http Status Code 設為 404 Not Found。
// if an error is thrown try to serve the asset at 404.html if (!DEBUG) { try { let notFoundResponse = await getAssetFromKV(event, { mapRequestToAsset: req => new Request(`${new URL(req.url).origin}/404.html`, req), }) return new Response(notFoundResponse.body, { ...notFoundResponse, status: 404 }) } catch (e) {} }
因此我們將這段程式修改成這樣:
// if an error is thrown try to serve the asset at 404.html if (!DEBUG) { try { let notFoundResponse = await getAssetFromKV(event, { mapRequestToAsset: req => new Request(`${new URL(req.url).origin}/index.html`, req), }) return new Response(notFoundResponse.body, { ...notFoundResponse, status: 200 }) } catch (e) {} }
這樣就可以在找不到檔案時遞送 index.html 給客戶端了,完成之後我們做一次打包,然後我們透過 wrangler dev
指令打開測試伺服器並訪問 http://localhost:8787 ,來看看設定是否正確。
~$ npm run build ~$ wrangler dev
在 Vue Application 的 Demo 頁面中就可以直接嘗試是否 History Vue Router 可以正常運作:
確定無誤之後我們就可以將其佈署至 Cloudflare Worker,最後我們訪問一下佈署的頁面:https://mysite.fres.host
~$ wrangler publish
就可以看到結果頁面:
Top comments (1)
第一次在 dev.to 看到台灣人的文,推一下!