0%

實作

新增兩個 LINE Channel key 至 .env

1
2
LINE_CHANNEL_TOKEN=
LINE_CHANNEL_SECRET_KEY=

接著加入 LINE 的 python SDK 至 requirements.txt

1
line-bot-sdk==1.12.1

透過 pip 安裝一下

1
pip install -r requirements.txt --user

在 controller/ 底下新增一個 message_api_controller.py 並輸入以下程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from flask import Flask, request, abort
from flask_restful import Resource
import json
import os
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.exceptions import (
InvalidSignatureError
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage,
)


class LineMessageApiWebhookController(Resource):
def post(self):
line_bot_api = LineBotApi(os.getenv('LINE_CHANNEL_TOKEN'))
handler = WebhookHandler(os.getenv('LINE_CHANNEL_SECRET_KEY'))

# get X-Line-Signature header value
signature = request.headers['X-Line-Signature']

body = request.get_data(as_text=True)
event = json.loads(body)
print(event)
try:
handler.handle(body, signature)
except InvalidSignatureError:
print(
"Invalid signature. Please check your channel access token/channel secret.")
abort(400)

token = event['events'][0]['replyToken']
if token == "00000000000000000000000000000000":
pass
else:
line_bot_api.reply_message(token, TextSendMessage(
text=event['events'][0]['message']['text']))
return 'OK'

用任何語言都會看到回傳會有 200, ‘OK’…回傳的成功訊息,在內部系統的部分在處理時要考慮到回傳時間的問題,一般來說如果回傳的時間大於 1 秒的話就有可能失效,或許有些朋友有測試過大於 1 秒也可以,但最好還是於時間內回覆哦!

以下圖片來自 https://engineering.linecorp.com/zh-hant/blog/line-device-10/

https://engineering.linecorp.com/zh-hant/blog/line-device-10/

接著在 api.py 加入下面兩段 code,新增一個webhook的路由

1
2
from controller.message_api_controller import LineMessageApiWebhookController
api.add_resource(LineMessageApiWebhookController, '/webhook')

這邊可以使用sls wsgi serve + ngrok去搭配做測試

接著就部署啦

1
sls deploy

現在在接這種第三方的 API 時最好都使用 https,而使用 Serverless 的好處就是 AWS 在部署完之後會送你一個含有 SSL 的網址~

把網址貼到 webhook URL 上並在尾端加上 /webhook

測試結果如下

結論

這次整合了以前寫的 Repo,加入了.env讓我在抓下來使用時也更方便,也整合成 Restful 格式讓之後有需要的人在看 code 時可以更容易理解了~

專案也會持續更新,更多詳情可以 follow 我的專案 aws-python-line-api

前言

今天會帶大家如何一步一步的建立 Message api 以及需要注意設定的地方。

實作

  1. 首先先到 https://developers.line.biz/zh-hant/ ,點選右上角的大頭貼並選擇 Add new provider
  2. 接著在 Provider name 填上自己的想要的名稱
  3. 再次確認
  4. 選擇想要使用那種服務,這邊我們就選擇Message API並按下Create Channel
  5. 接著就開始填寫自己的機器人(channel)所需要的資訊嚕!
  6. 這邊我們需要填寫的內容為
    6.1. 大頭貼(option)
    6.2. 名稱 App name (required)
    6.3. 描述 app description (required)
    6.4. 類別與子類別 Catagory (required)
    6.5. 信箱 Email address (required)
    6.6. 政策網址 Policy URL (option)
    6.7. 服務條款網址 Term of use URL (option)



  1. 當填寫完之後的寫一步最後會需要勾兩個服務說明確認的選項並按下 Create
  2. 如此一來就看到自己百般折騰建立出來的 Message api 啦
  3. 滑到最下面,首先掃描 QR code 加入自己機器人的好友讓接下來好測試,接著按下圖篇右手邊的 Set message 進入調整頁面
  4. 進入之後到下面,將歡迎訊息 & 自動回應 停用,並將 Webhook 打開,讓之後的串接可以透過 Webhook 打到 Serverless 上,若是前兩個回應的選項沒有關的話即使 Webhook 有啟動也會因為優先權問題被擋下來哦!

簡介

LINE 在 2016 年 9 月底發表了 Messaging API 功能,用戶可以透過 Messaging API 將自家的服務內容串聯到 LINE@ 上。

接著在 2019/04/18 之後 LINE@ 2.0 正式上線,在 5/22 後有升級的選項並會陸續更新,升級完的官方帳號也可以申請專屬 ID、進行帳號認證。

我認為比前一版本的最大的好處是在好友無上限的這部分,以前只能有 50 位好友,若一般開發者的機器人好不容易上線了並開放測試時被限制住,除了再開一隻機器人或是其他方法就超麻煩,現在好友無上限了,就不會有上述的問題了。

若您以前有開發過的機器人到現在還沒升級的話,可以參考 -> URL

這邊需要注意 1 on 1 聊天與 Messaging API 是無法同時使用的,但可以在後台切換看要使用哪種模式與顧客互動。對話記錄也會保存在各自的模式下,若要查看完整的對話記錄的話會建議以固定模式與顧客進行互動哦!

主要的功能環繞在以下兩點

  1. Push mode: 主動推播訊息給用戶,2.0 每個機器人都有 500 則免費推播則數,超過則數的話可以參考以下的價目表:

  1. Reply mode: 這個模式是接受使用者的訊息並透過 webhook 打到伺服器上讓伺服器去做對應訊息的處理,重點是它是是免費、免費、免費的!所以若能引導使用者去輸入訊息的話用這個模式是不用錢的哦 🎉

Message API 支援以下格式

  • Text message
  • Sticker message
  • Image message
  • Video message
  • Audio message
  • Location message
  • Imagemap message
  • Template message
  • Flex message

詳細內容可以參考 LINE doc

line sample 1
line sample 2

回傳格式

Message API 回傳格式都是一個陣列的格式,一開始在接的時候都沒注意到一直瘋狂出錯,事實上這樣陣列對 Server 有個好處就是當一次需要送較多訊息時格式會比較統一,只是對於有潔癖的開發者來說每次都要多打[0]會覺得有點髒 🤣

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
'events': [{
'replyToken': '00000000000000000000000000000000',
'type': 'message',
'timestamp': 1568983962754,
'source': {
'type': 'user',
'userId': 'Udeadbeefdaaaaefdeadbeefdeadbeef'
},
'message': {
'id': '100001',
'type': 'text',
'text': 'Hello, world'
}
}, {
'replyToken': 'ffffffffffffffffffffffffffffffff',
'type': 'message',
'timestamp': 1568983962754,
'source': {
'type': 'user',
'userId': 'Udeadbeeaaaaefdeadbeefdeadbeef'
},
'message': {
'id': '100002',
'type': 'sticker',
'packageId': '1',
'stickerId': '1'
}
}]
}

結論

以前剛開始接 LINE Message API 的時候都覺得他的文件不太人性,更新到現在文件內容也越來完整,讓開發者在開發的過程中不用再為了找不到文件而放棄了(我以前就是 🤣),下一篇將會帶來如何申請一隻機器人到如何建立一個 webhook API 到 AWS 上

參考

功能介紹】Messaging API
LINE message template

首先先建立一個consumer/資料夾,新增__init__.py以及notify_handler.py

notify_handler.py輸入以下程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import json
import requests


def line_notify_handler(event, context):
print(event)
body = json.loads(event['Records'][0]['body'])
print(body)
headers = {
'Authorization': f"Bearer {body['token']}",
'Content-Type': 'application/x-www-form-urlencoded'
}
r = requests.post('https://notify-api.line.me/api/notify',
headers=headers,
data={'message': body['message']})
print(r)

# AWS record sample
# {'Records': [{'messageId': 'fddc42ba-a122-4581-965e-d0144ac8a5ad', 'receiptHandle': 'AQEBjO32gY5pXOfOrmDR0hD4k1av9KyjbHFpc+rIBPV2Brif7Lo+jqnGevSjfFwlICyGf+BhWwKaxFw8XdB3QTzRbw0vnLURjnQeDSBrJHa/S57SRs9TOLRBq38maycAVg69iZbetg9VhLMBCcLtOtPHTzKkmo+/Sosm51WA5CzXK7A0rteikx6nxS1CUIpq6MAujodupP0Hgr5RjK5nH/nmxA4Db0leWEmLokalZbtlx4W14tp7PZxPOrQOLDaGrH//p4h32tY8IN3MkCqi+gyNT7kCU4KwCGOIrybb07ZWyKBTKw+KOMNr/Ykj4z2N1qxIvTM55UY9d8V29YsH32OjrZTei5P7Nke/51E2tWkmkqoFAlqzxDjQPvpP+Pvvr8aazeeZ6opkr59UefAiiyM71Q==', 'body': 'hi', 'attributes': {'ApproximateReceiveCount': '9', 'SentTimestamp': '1566621263072', 'SenderId': '901588721449', 'ApproximateFirstReceiveTimestamp': '1566621263072'}, 'messageAttributes': {}, 'md5OfBody': '49f68a5c8493ec2c0bf489821c21fc3b', 'eventSource': 'aws:sqs', 'eventSourceARN': 'arn:aws:sqs:us-east-1:901588721449:LINE_notify_consumer', 'awsRegion': 'us-east-1'}]}

接著在requirements.txt加入boto3,他是一個使用 python 介接 AWS 的套件

1
boto3==1.9.189

加入SQS_URL以及SQS_ARN.env裡面

1
2
SQS_URL=sqs url
SQS_ARN=your sqs arn

add controller/notify_sqs_controller.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
from flask_restful import Resource, reqparse
import json
from lib.db import Database
import psycopg2.extras
import os
import boto3


def send_message(url, attr, body, delay=0):
cli.send_message(
QueueUrl=url,
DelaySeconds=0,
MessageAttributes=attr,
MessageBody=body,
)


class SendNotifyBySQSController(Resource):
cli = boto3.client("sqs", region_name=os.environ("region"))

def post(self):
parser = reqparse.RequestParser()
parser.add_argument(
'message', required=True, help='message can not be blank!')
args = parser.parse_args()
msg = args['message']
with Database() as db, db.connect() as conn:
with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur:
cur.execute(
f"SELECT token FROM notify")
fetch = cur.fetchall()
for f in fetch:
body = {
'token': f"Bearer {f['token']}",
'message': f"Hello everyone, {msg}"
}
cli.send_message(
QueueUrl=os.environ("SQS_URL"),
DelaySeconds=0,
MessageAttributes={},
MessageBody=json.dumps(body),
)
return {'result': 'ok'}, 200

程式寫完了就是要加一條路由/notify/sqs

1
2
from controller.notify_sqs_controller import SendNotifyBySQSController
api.add_resource(SendNotifyBySQSController, '/notify/sqs')

接著透過wsgi在本地起一個 server

1
sls wsgi serve

再搭配 postman 來做測試,測試內容如下

1
2
3
{
"message": "test Content"
}

接著透過sls deploy部署上會遇到一個問題,會有 Access Denied,所以要在serverless.yml加入 IAM role 的設定

add iam in provider

1
2
3
4
5
6
iamRoleStatements:
- Effect: Allow
Action:
- sqs:SendMessage
Resource:
- ${env:SQS_ARN}

測試


結論

使用 SQS 這類服務都會需要透過boto3來幫忙串接,最需要注意的就是 IAM role,因為在本地端的 key 通常權限都是最大的,但上到 AWS 上就會有權限的問題,所以要記得加入 IAM 哦!

Code is here

專案也會持續更新,更多詳情可以 follow 我的專案 aws-python-line-api

詳細介紹

以前自己在架伺服器的時候,提到訊息佇列不外乎都是 RabbitMQ 或是 Kafka,只是現在 AWS、GCP 這類的雲端平台都越來越火紅了,手動按一下服務就建好了(信用卡也在哭泣),省去很多建立服務的時間,只是說一般時候根本找不到項目練習 😓,剛好最近在複習 LINE Notfiy,就趁這個機會順便練習並記錄一下 ✌️

你需要先了解…

當 Http requests 非常大量到一定程度,database 已經跟不上處理的速度,尤其是 relational database,這時就需要 queue 來緩衝;所以社群網站像 Facebook or LinkedIn 都使用大量的 message queue and cache.
By -> Leonard Lee

SQS 就是 managed queue service,主要就是 async, central messaging (對相對應的程式來說,通常處理 api 的會有多個 instances 同時存在,像是 auto-scaling),像是 fb 通知、寄送 email 認證信這種不用即時處理的情況,只要給訊息給 queue 讓其他服務或程式去處理,可以把原本的邏輯簡化(以及責任區分),甚至些事件是預期同時會有多個 listener 會需要處理的情況,在一個 api 裡面去處理這些會讓邏輯變很複雜/不好維護。
By -> Bill Chung

還有就是如果負責處理 request 的 host 有問題,message queue 可以用來短暫儲存還未被處理的 requests 使他們不至於丟失,直到 host 回復正常或是換了一個好的 host 後,message queue 裡面的的 requests 就可以繼續被處理
By -> 盧元駿

以上來自我之前寫過的文章 使用 Serverless 讓 AWS SQS 幫你發送 LINE Notify

今天在需要發個請求去呼叫 LINE API(或是其他服務的 API),都可能會碰到圖片,圖片不管他怎麼壓縮,終究還是比文字肥,在數量多的情況下可能就會發現 API 罷工(就會像被斷詠唱一樣)。雖然平常使用可能不會這麼平凡呼叫,但若在商業用途上使用者多的時候一次呼叫就會有一大筆,這時候用 Queue 讓他們排隊一個一個來就在適合不過了 🎉。

為什麼選擇 AWS SQS

Amazon Simple Queue Service (SQS) 是全受管訊息佇列服務,可讓您分離和擴展微型服務、分散式系統及無伺服器應用程式。SQS 可免除與管理和操作訊息導向中介軟體相關的複雜性及開銷,也可讓開發人員專注在與眾不同的工作上。您可以使用 SQS 在軟體元件之間傳送、存放和接收不限數量的訊息,不會遺失訊息或需要其他服務可用。使用 AWS 主控台、命令列界面或自選的 SDK 以及三個簡單的命令,即可在幾分鐘內開始使用 SQS。(參考 AWS)

SQS 有在免費方案裡面,只要一個月別高於 100 萬個請求就不會被收錢啦 💪

AWS 的免費方案可以參考 -> LINK

建立 SQS

接著就要開始引入 SQS 嚕,首先到 AWS 上的 SQS 頁面,如下


接著選左邊的Standard Queue並填入 name 就好


建立完之後就可以看到下面有建立完的資訊

ARN 以及 URL 接下來都會用到哦

結論

接下來會帶各位使用 Notify 接在 SQS 上,這篇就先帶各位介紹並先手動建立一個 Queue,之後會在大家使用 python 的 boto3 的套件來搭配使用 AWS 服務使用 👏

前言

看著前幾天的文章,像我們 notify 驗證的 API 有使用到 REDIRECT_URICLIENT_ID 以及 CLIENT_SECRET,或是像 PostgreSQL 的帳號密碼,
只是說若今天當程式碼變多的時候,抑或是這個參數有給其他 API 使用,那在尋找的時候不僅費工又浪費時間
那接下來就帶著大家在 serverless.yml 一步步加入變數值,並更改 code。

動手吧!

用 npm 安裝 serverless 的 dotenv 套件

1
npm i -D serverless-dotenv-plugin

接著加入新的套件到serverless.yml

1
2
plugins:
- serverless-dotenv-plugin

新增dotenv到 requirements.txt

1
python-dotenv==0.10.3

到 api.py 加入下面內容

1
2
3
from dotenv import load_dotenv
env_path = Path('.') / '.env'
load_dotenv(dotenv_path=env_path)

接著新增.env並輸入對應的內容

1
2
3
4
5
6
7
8
9
10
11
NOTIFY_REDIRECT_URI=
NOTIFY_CLIENT_ID=
NOTIFY_CLIENT_SECRET=
REGION=us-east-2
SQS_URL=
SQS_ARN=
PG_DB=
PG_HOST=
PG_NAME=
PG_PWD=
PG_PORT=

接著修改有使用到他們的地方,範例如下

1
2
import os
os.getenv("SQS_ARN")

既然有安裝 serverless 的套件了,那 yml 檔也可以使用哦!

1
2
3
4
provider:
name: aws
runtime: python3.7
region: ${env:REGION}

後記

有時候把專案抓下來的時候要找到這些輸入的地方很容易找不到(我有點癡呆),一般 open source 也都會有一個.env的,用serverless-dotenv-plugin來幫忙弄就方便許多了,後續有需要再繼續往裡面新增就好了~

最後在搭配 python 的 dot env 套件使用就讓整個好用多了 🤣,只是說 html 因為目前還不是透過 serverless 來幫忙部署,所以這邊的參數就沒辦法吃設定檔了 😓

參考

os.environ
env setting

繼上一篇我們已經可以讓使用者註冊 Notify 並將 token 放入資料庫,接著就帶各位使用 query string 的方式讓你的 Notify 可以送訊息給所有註冊過的 Notify。

首先我們進入我們已經建立過的 controller/notify_controller.py,會看到 class 下有我們之前建立的 post method,這時我們就在前面加入 get method,並加入以下的 code,讓這個 class 看起來比較有順序(潔癖)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from flask import request

class NotifyController(Resource):

def get(self):
msg = request.args.get('msg')
with Database() as db, db.connect() as conn:
with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur:
cur.execute(
f"SELECT token FROM notify")
fetch = cur.fetchall()
for f in fetch:
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': f"Bearer {f['token']}"
}
payload = {'message': msg}

r = requests.post(
'https://notify-api.line.me/api/notify', data=payload, headers=headers)
return {'result': 'ok'}, 200

def post(self):
...

這次使用的套件比上次多 import 一個 flask 底下的 request (注意沒有 s 哦),這個主要是讓我們可以抓到網址問號後面接的參數,這邊我設定打 API 的人會打一個 msg 的參數。

接著就是使用進 DB 撈我們的 token 們,並用一個迴圈來跑

再來是設定 headers 以及 payload

headers 的部分參考 Notify 的文件,如下圖

我們需要設定 Content-Type 以及 Authorization,需要注意的是 Authorization 是使用 Bearer 格式(參考),他中間是有加空白鍵的,這邊很多朋友都會錯在這裡,千萬要記得檢查這邊!

接著是要送出去的東西是要用什麼送出,本篇只用 message 做範例,若需要使用到其他的功能,像是圖片、貼圖等等的可參考以下的圖片

接著我們就可以使用sls deploy來部署我們的程式啦

等等!
這邊有個需要注意的地方是,照著這次的範例使用的話會需要用 docker 來幫忙跑編譯,因為 psycopg2-binary 這個套件如果不是在 Linux 的環境下會需要透過 docker 幫忙編譯完再丟過去
這部分需要在serverless.yml下填入參數

1
2
3
custom:
pythonRequirements:
dockerizePip: true

如此一來當前環境若不是 Linux 的話他就會使用 docker 來幫忙,記得 docker 要開哦 🙏

當然最簡單的方法就是把它直接抓下來放在專案中,只是這樣就會比較髒一點,可以從這邊抓 -> 參考

這邊可以先在環境變數上加上SLS_DEBUG=* 接著在加上 sls deploy 後面加上--verbose可以看到 serverless 到底都在背地裡做了什麼事情 🤣

接著我們就使用 Postman 來幫我們送字串出去,參考下圖,當回傳 ok 就成功了 🎉

你的 Notify 應該要回你了~

結論

這邊帶大家做一個簡單的應用,一般來說我覺得放在 query string 讓其他 API 來呼叫的時候帶參數來就可以直接用是很方便的,不用再特地自己寫方法去呼叫 LINE Notify 來幫我們送,反正 AWS Lambda 有一百萬次的請求不怕 🤣

建立 LINE Notify 服務

第一步先到 LINE Notify 管力登入服務去建立一個服務

接著按下登入服務

把該填的填一填,要注意的是 Callback Url 這邊先暫時先打 localhost:5500,等頁面上傳後再回來改 domain


建立完成之後就到剛剛填的信箱去收信點下網址並啟動服務

這樣第一步就建立完成嚕!

動工

接著上次的透過上次的專案並使用 flask_restful 來改造成 Restful 格式的專案(後面開發會比較輕鬆)
因為我們會讓前端呼叫,CORS 設定成*比較輕鬆,若是有要設定跨域問題的在這邊設定哦 👏
加入套件到 requirements.txt

1
2
3
4
flask==1.0.2
Flask-RESTful==0.3.6
Flask-Cors==3.0.6
requests==2.22.0

透過使用 flask_restful 幫忙轉發並管理路由
將 api.py 改為以下的 code

1
2
3
4
5
6
7
8
9
10
11
12
13
from flask import Flask
from flask_restful import Api
from flask_cors import CORS
from controller.notify_controller import NotifyController

app = Flask(__name__)
CORS(app, resources={r"*": {"origins": "*", "supports_credentials": True}})
api = Api(app)

api.add_resource(NotifyController, '/notify')

if __name__ == '__main__':
app.run(debug=True)

這邊我使用 Postgresql,並在專案底下建立一個 lib/ 的資料夾,裡頭放著名為 db.py (這裡還是要記得建立 init.py 哦!)
這邊只簡單建立 Context Manager 讓連線可以被我呼叫。
db.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import psycopg2
import psycopg2.extras

class Database():
conns = []
def __enter__(self):
return self

def connect(self):
conn = psycopg2.connect(
database=PG_DB,
user=PG_USER,
password=PG_PWD,
host=PG_HOST,
port=PG_PORT
)
self.conns.append(conn)
return conn

def __exit__(self, type, value, traceback):
for conn in self.conns:
conn.close()
self.conns.clear()

新增一下資料夾名為 controller,建立 init.py & notify_controller.py,這邊搭配 with 做資源管理器,
DB 部分則見黎一個 notify 表,然後一個 token 的欄位。

在這個 class 類別下方法只要輸入 def get/post/put/patch/delete 的函式就可以對應 CRUD 的功能了!

notify_controller.py code is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from flask_restful import Resource, reqparse
import requests
import json
from lib.db import Database
import psycopg2.extras

class NotifyController(Resource):
def post(self):
parser = reqparse.RequestParser()
parser.add_argument('code', required=True, help='code can not be blank!')
args = parser.parse_args()
code = args['code']
client = {'grant_type': 'authorization_code', 'code': code, 'redirect_uri': 'YOUR_REDIRECT_URI',
'client_id': 'YOUR_CLIENT_ID', 'client_secret': 'YOUR_CLIENT_SECRET'}
r = requests.post(
'https://notify-bot.line.me/oauth/token', data=client)
req = json.loads(r.text)
if req['status'] == 200:
token = req['access_token']
# Here is use PostgreSQL, you can change your love db
with Database() as db:
with db.connect() as conn:
with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur:
cur.execute(
f"INSERT INTO notify(token) VALUES ('{token}')")
return {'access_token': req['access_token']}, 200
else:
return {'message': r.text}, 200

以下這三個要設定成你的當時輸入的字串

  • YOUR_REDIRECT_URI
  • YOUR_CLIENT_ID
  • YOUR_CLIENT_SECRET

若不清楚 Client_id & Client_secret 的話就回到 Notify 頁面並點選剛剛建立的服務就能看到 token 了

建立一個 views/ 的資料夾,並建立兩個檔案

  • notify_index.html

    這邊需要修改 client_id 以及 redirect_uri
    這個檔案主要功能是讓使用者有個可以按按鈕觸發的地方,當然這只是個範例,實際上線可能就會直接 call API 導向 LINE Notify 頁面等等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Link Notify</title>
</head>
<body>
<button onclick="Auth();">點選這裡連結到LineNotify</button>

<script>
function Auth() {
var URL = "https://notify-bot.line.me/oauth/authorize?";
URL += "response_type=code";
URL += "&client_id=YOUR_CLIENT_ID";
URL += "&redirect_uri=YOUR_REDIRECT_URI";
URL += "&scope=notify";
URL += "&state=nostate";
window.location.href = URL;
}
</script>
</body>
</html>
  • notify_confirm.html

    修改 ajax 裡的 url,將網址換成之前部署的網址,若忘了可以在部署一次 sls deploy
    當導回來的時候透過 ajax 來呼叫 serverless api 讓後端發 requests 給https://notify-bot.line.me/oauth/token來獲取access_token

因為這個路由有 CORS 的問題,若透過瀏覽器來的話會出錯,這邊則是讓後端去處理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>message check</title>
</head>
<body>
verify messate:
<div class="message"></div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script>

<script>
var urlParams = new URLSearchParams(window.location.search);
var notify_code = urlParams.get("code");
var state = urlParams.get("state");
$(function() {
$.ajax({
url: "https://SLS_URI.execute-api.us-east-2.amazonaws.com/dev/notify",
type: "POST",
dataType: "json",
data: { code: notify_code },
success: function(response) {
console.log(response);
$(".message").text(response["access_token"]);
},
error: function(xhr) {
console.log(xhr);
alert("Ajax request 發生錯誤");
}
});
});
</script>
</html>

接著就是測試程式碼是不是正常的,把這兩個檔案丟到 S3 上面


把 object url 複製到 LINE Notify 上的 callback url 欄位,這樣就可以實機測試了 🤣

接著按下 index page 的按鈕應該就會看到連動成功(進資料庫應該也會被 insert 一筆)

到了這邊如果沒問題真的是恭喜你,我踩了好多坑 Orz

參考

資源管理器
flask CORS
CORS

前言

Amazon Simple Storage Service(簡稱 AWS S3)是 AWS 的一個線上儲存服務,用戶能夠輕易把檔案儲存到網路伺服器上,可能有些朋友會把它當成雲端硬碟看待,但其實還能像是傳靜態檔案上去,若有寫前端框架的朋友通常都會需要把程式碼打包成靜態檔案再部署,然而這邊把他打包送上去後,S3 會給一個名為 Object Url 的網址,可以透過這個網址去執行網頁裡面的內容(如 AJAX、Axios…),並可以透過 cloudfont 去弄成 CDN(扯遠了),簡單說他還有很多不一樣的功能應用等著大家去用~

因為 serverless 只能放關於 API 的程式碼,因此我們需要把 html 靜態檔案放在 S3 裡,

接下來就來建立一個公開的 S3 容器,這邊就不會提到權限如何控管哦!

建立一個公開的 S3 容器

建立一個名為2019-it-30-bucket的容器,地區就選與 Lambda 同樣的地區,直接按下左下角的create來建立。

建立完會像這樣

接著點進去後在點到第三個選項會看到 Block of public access 是啟動的狀態,因為我們接下來需要讓我們的頁面可以外部使用

就把 check box 的按掉,在按下 Save

要輸入confirm就修改完成嚕

接著一樣點到第三個個選項,選到Access Control List,看到Access for bucket owner這個選項的Canonical ID,選項都全部打勾之後再來調整,這樣之後的 HTML 檔案外面就看得到了。

測試

接著上傳一個index.html的檔案來測試

1
2
3
<html>
<h1>Hello world</h1>
</html>

上傳後下拉式選單選擇public read的選項,因為一個檔案在 S3 就算是一個 Object,所以一定要讓它能對外,然後按下左下的 Upload

成功後點進這個檔案,並按下方的Object URL,看到 Hello World 的話就代表成功囉,這時可以開個無痕測一次,確認一下沒有錯誤 😃

參考

AWS S3 wiki

LINE Notify 顧名思義就是通知屬性的服務,這個服務不是 LINE 的 Message API,千外別把這兩個搞在一起哦!

在實作前要先認識一下在接的 api 服務原理
首先先參考LINE Notify 官網
開頭的介紹:

Overview: Becomes a provider based on OAuth2 (https://tools.ietf.org/html/rfc6749). The authentication method is authorization_code. The access token acquired here can only be used for notification services

不負責任翻譯: 這個服務是基於 OAuth2 實作的,授權模式(grant_type)是 authorization_code 參考
access_token 則是只能讓通知服務所使用的一個鑰匙

1
更詳細的流程可以參考 https://blog.yorkxin.org/2013/09/30/oauth2-4-1-auth-code-grant-flow.html

The host name for authentication API endpoint is notify-bot.line.me.

然後 API 的網址是 notify-bot.line.me

接著我們來看看流程圖
https://notify-bot.line.me/doc/en/

  • 當使用者拜訪你的網站時,會導向 LINE 請求認證
  • 認證過了之後會回傳一個名為 code 的參數
  • 接著網站需要持這個 code 在去找 LINE 討東西
  • 討成功後就會拿到一個 access_token
  • 網站就會知道這個 access_token = 來註冊的使用者
  • 然後就可以透過 access_token 發送通知給使用者了?

事前準備

首先就是要先加入他好友,如果之前有不小心封鎖的話要記得解除封鎖哦,不然後續會收不到消息。
https://ithelp.ithome.com.tw/upload/images/20190903/20111481Zno98NSHwL.png

下一篇會帶著時做出簡單的 index.html + 使用 Serverless 蓋我們第一個 API 來做認證。
會使用到 LINE Notify 的 API 為以下三個,不清楚裡面實際上功能的朋友可以嗑一下官網文件

1
2
3
GET https: //notify-bot.line.me/oauth/authorize -> 前往認證拿到 code 參數
POST https://notify-bot.line.me/oauth/token -> 拿 code 參數換 access_token
POST https://notify-api.line.me/api/notify -> 發送訊息

其他

今年中有帶著朝陽的學弟妹手把手實作 LINE Notify,如果只想自己用的話可以參考我之前簡報

LINE Notify
如何快速建置一個 LINE Notify 的服務