Cloud Run
串接Line發送通知這種東西以前就想玩玩看了,最近剛好有個機會就來試試看了。我的使用情境大概是這樣:有個自動化的搶訂單網頁腳本,在取得訂單號碼後30分鐘內要匯訂金,完成後這張訂單才算成立,但人不可能隨時都在電腦前面顧著,這樣一點都不自動化。這時候用Line來發送記得匯訂金的通知就很方便了。
直接在前端JS呼叫Line BOT的API
經過詢問ChatGPT後,一開始給我的範例如下:
<script>
async function sendLineMessage(msg)
{
const CHANNEL_ACCESS_TOKEN = "你的Channel Access Token"; // 長期有效 token
const USER_ID = "Uxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; // 接收者的 User ID
fetch("https://api.line.me/v2/bot/message/push", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${TOKEN}`
},
body: JSON.stringify({
to: USER_ID,
messages: [
{ type: "text", text: msg }
]
})
})
.then(res => res.json())
.then(data => {
console.log("LINE API 回應:", data);
alert("訊息已發送");
})
.catch(err => {
console.error("發送失敗:", err);
});
}
</script>CORS
看起來雖然也是有模有樣的,但實際上一執行後,卻出現了CORS的問題。

順便附上Gemini的問答紀錄
問:
前端Javascript是不是沒有辦法直接設定"Access-Control-Allow-Origin"為*來避免CORS的問題答:
您好,您提到的這個問題很常見,這是一個關於 CORS(跨域資源共享) 的經典迷思。
前端無法設定 Access-Control-Allow-Origin 的原因
Access-Control-Allow-Origin 這個 HTTP 標頭(Header)是伺服器端用來告訴瀏覽器,它願意讓哪些「來源」(Origin)的網頁來存取它的資源。
簡單來說:
當您在 A 網域的網頁上,透過 JavaScript 呼叫 B 網域的 API 時,瀏覽器會發出一個跨域請求。
這個時候,B 網域的伺服器需要在回覆的 Response Header 中,設定 Access-Control-Allow-Origin,並且它的值需要包含 A 網域,或者設定為 * 來允許所有來源。
如果伺服器沒有設定這個 Header,或者設定的值不包含您的網頁來源,瀏覽器就會基於安全政策,阻擋這個跨域請求,並在 Console 中拋出 CORS 錯誤。
因此,前端的 JavaScript 程式碼沒有權限去設定 Response Header。這是因為 HTTP Response Header 是由提供資源的伺服器所決定的,前端只能處理和發送 Request Header。
如何解決 CORS 問題?
既然前端無法自行解決,那麼解決 CORS 問題的根本方法,就是從伺服器端著手:
修改 API 伺服器設定:
這是最直接、最根本的方法。如果您有權限修改 API 伺服器的程式碼,只需在伺服器的 Response Header 中,加上 Access-Control-Allow-Origin: *。
但為了安全,更推薦的做法是只指定特定的來源,例如:Access-Control-Allow-Origin: https://your-frontend-domain.com。
使用代理伺服器(Proxy):
如果您無法修改 API 伺服器,或者出於安全考量不想直接開放 CORS,那麼可以自己建立一個代理伺服器。
前端的 JavaScript 程式碼向您自己的代理伺服器發送請求(這是同源請求,不會有 CORS 問題)。
代理伺服器收到請求後,再去向真正的 API 伺服器發送請求,取得資料後再轉發給前端。
由於伺服器之間的請求沒有同源策略的限制,所以可以順利拿到資料。
現在許多前端框架或工具(如 webpack-dev-server、Vite)都內建了代理伺服器的功能,可以讓您在開發時輕鬆設定,這是很常見的解決方案。GCP Cloud Run
為了解決上面CORS的問題,但又覺得為了一個實驗性質的測試小API特地開一個.Net Core WebAPI專案,在部屬到遠端Server實在是有點懶。於是問了一下ChatGPT後,發現有GCP Cloud Run這種好東西。
GCP Cloud Run介紹
Cloud Run 是代管運算平台,能讓您在 Google 可擴充的基礎架構上直接執行容器。
只要能從程式碼建構容器映像檔,您就能在 Cloud Run 上部署以任何程式設計語言編寫的程式碼。事實上,建立容器映像檔是選用步驟。如果您使用的是 Go、Node.js、Python、Java、.NET Core、Ruby 或支援的架構,可以利用「以來源為基礎的部署」選項,透過所用語言的最佳做法來建構容器。
(source:什麼是 Cloud Run?)
GCP Cloud Run啟用流程
先到GCP的console頁面,在上方收尋欄位搜尋Cloud Run。

點選建立服務按鈕

我這邊懶人作法直接使用內嵌編輯器建立函示,並把地區選到台灣,其餘選項都用預設項目,好了之後點選建立。

可以看到下面的預設畫面,為一個線上編輯器


原始碼
index.js
const functions = require('@google-cloud/functions-framework');
const fetch = require('node-fetch');
const TOKEN = ""; // 長期有效 token
const USER_ID = ""; // 接收者的 User ID
functions.http('sendLineMessage', async (req, res) => {
// 設定 CORS
res.set("Access-Control-Allow-Origin", "*");
res.set("Access-Control-Allow-Methods", "POST, OPTIONS");
res.set("Access-Control-Allow-Headers", "Content-Type");
// 處理預檢請求
if (req.method === "OPTIONS") {
return res.status(204).send('');
}
// GET 測試路徑
if (req.method === "GET") {
return res.status(200).send("✅ LINE Proxy Service is running");
}
if (req.method === "POST") {
try {
const { message, to } = req.body || {};
const r = await fetch("https://api.line.me/v2/bot/message/push", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${TOKEN}`,
},
body: JSON.stringify({
to: to || USER_ID,
messages: [{ type: "text", text: message || "No message" }],
}),
});
const data = await r.json();
return res.status(200).json(data);
} catch (err) {
console.error(err);
return res.status(500).send("發送失敗" + err);
}
}
// 其他方法
res.status(405).send("Method Not Allowed");
});package.json
{
"dependencies": {
"@google-cloud/functions-framework": "^3.0.0",
"node-fetch": "^2.6.7"
}
}API測試
部屬完成後,複製網址。

貼到API測試軟體測試看看

成功!

Ref: