網頁後端 Flask

講師介紹:

成電CKCSC 38th - 教學 + 網管

翁釩予 MLGnotCOOL

@mlgnotcool

 

自我介紹網站?

(可以看出來為什麼我是教後端不是前端)

講師介紹:

興趣?(除了扣丁之外)

講師介紹:

學術力:

競程、演算法、網頁設計、python

APCS 中高級 5+4、北市賽三等獎 第17名

(對是打競程的我不知道為什麼我來講後端了 :P)

歐對 我打字很快算學術力嗎 :P

後端

是什麼可以吃嗎?

伺服器

伺服器本質上是一台 24 小時不關機的強力電腦

 

伺服器

工程師在伺服器的工作主要有:

  • 配置環境:決定要用哪種作業系統(通常是 Linux)和運行環境。
  • 部署程式:將寫好的程式碼「放」到伺服器上,讓全世界的使用者都能訪問。
  • 監控狀態:確保網站不會因為人太多而當機。當流量突然暴增(例如雙 11 搶購)時,工程師需要透過「負載平衡」技術來分流壓力。
  • 管理資料和網站的安全性以降低網路攻擊的風險。

 

Linux (小補充)

資料庫

處存使用者資訊的地方

 

每一筆使用者註冊的帳號、發出的評論、購買的紀錄,都必須被安全且有序地存放。

  • CRUD 運作:這是後端最基礎的四個動作:新增 (Create)、讀取 (Read)、更新 (Update)、刪除 (Delete)。
  • 資料安全:確保使用者的密碼有經過加密處理,即便資料庫被駭,駭客也無法直接讀取明文。

什麼是後端?

就是在伺服器處理前端不能處理的東西

例如:密碼登入之類的東西

什麼是後端?

前端:你看的到的

後端:伺服器處理的

什麼是後端?

沒有後端的網站 -> 靜態網站

有後端的網站 -> 動態網站

處理後端的程式語言有非常多種:

像是 php, javascript, python 之類的

 

其中python應該是最檢顯易懂的程式語言,

而我們今天要教的是python的Flask函式庫,專門來處理網頁後端的

什麼是後端?

來看看一個有後端的網站吧

100%不是我寫的扣

Flask

簡介

錐形瓶?

python web framework

flask

Flask

Flask

延續剛剛學會的後端,Flask就是專門來處理後端這部分的python函式庫

Flask

Flask可以用來處理很多關於後端的東西,例如route, API之類的。

因為是用python寫的,所以非常的檢顯易懂,但是相較其他寫後端的程式語言,它的功能或許比較少,也比較慢。

python web 框架

剛剛介紹了Flask,是一個python的web framework,但是其實也有其他的python web framework,像是fastAPI和Django

python web 框架

剛剛介紹了Flask,是一個python的web framework,但是其實也有其他的python web framework,像是fastAPI和Django

Django FastAPI Flask
類型 全能型框架 微框架 微框架
效能 在大型網站快 處理API和小網站快 相對比較慢
難度 高 低 低
好處 在大型網站使用時,可以做到非常快 在處理API或小型網站時,可以非常快 在作小型網站時,非常的簡易且修改
(很輕)

Flask

下載

Python

(就看你現在這台電腦有沒有載吧)

 1. 下載python:網站

2. 在vscode確認有沒有選對的版本:

Flask

如何使用Flask

1. 先在vscode建立一個簡單的前端網站

(我相信你們學過 還記得怎麼作)

Flask

如何使用Flask

2. 下載vscode的python extension

Flask

如何使用Flask

3. 下載Flask package

pip install Flask

開啟terminal

打入這個指令

Flask

小插入 先解釋一個檔案再電腦中的途徑

那要怎麼從一個檔案走到另一個檔案呢?

(讓html知道我們的檔案在哪裡)

假設我們要從index.html走到funny.png:

一些要知道的小知識:

"." - 現在這個資料夾

"/" - 要走的途徑

".." - 返回上一層資料夾

 所以就會是:(拿前端的link來當例子)

<link href="./images/funny.png" rel="icon">

Flask

如何使用Flask

4. 建立一個python檔案 (.py)

5. 檔案結構(Flask才能運作)

html 放 ./templates

css 放 ./static/css

js 放 ./static/js

圖片放 ./static/images

Flask

如何使用Flask

請大家先做到這步

(接下來就要叫大家打扣了)

 

(也可以先寫個前端idk)

Python

基礎語法

Python

(這裡預設你已經有學過一些程式語言)

變數

a = 10 #整數
b = 20.2 #小數
c = 'string' #字串
d = [10, 30, 40] #陣列

# 對不需用跟他說是什麼類型

Python

if

a = 10
b = 20

if a == 15:
  print("a is 15")
elif b == 20:
  print("b is 20")
else:
  print("neither is true")
  
 #對 python 不用小括號
 #對 python 不用分號
 #對 python 不用大括號 (不下放btw)

Python

while

a = 10

while a < 20:
  print(a)
  a += 1
  
 # 應該蠻直觀的

Python

for

# 重複10次
for i in range(10): #i 會是 0~9
  print(i)
  
for i in range (2, 19, 2): #如果翻譯成c++或js就會是 for (int i=2; i<19; i+=2)
  print(i)
  
arr = ["apple", "banana", "tomato"]
for i in arr: #i 會是 arr 中的元素
  print(i) 
  

Python

function

def add(a, b):
  ans = a+b
  return ans

print(add(1, 2))

#python宣告函式的方法是def
#剩下就和其他語言差不多了

Python

f string

fruit = "apple"

print(f'My favorite fruit is {fruit}')
#可以在字串中加入變數 很好用

Flask

語法

Flask

from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
    return "Hello, World!"

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

基礎模版

除了3-5行之外

大致上都是複製貼上 可以先不用理解

 

(只要知道他導入Flask

然後可以讓網站跑就好了)

Flask

基礎模版

第3行 - 裝飾器

 

第4-5行 - 函式

當我們載入網站時會跑的函式

from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
    return "Hello, World!"

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

Flask

@app.route("/a")
def helloa():	
    return "Hello, World! aaa"

這個函式跑得網站:

http://127.0.0.1:5000/a

from flask import render_template

@app.route("/a")
def hellob():
    name = "John"
    return render_template("index.html", name=name)
<h1>Hello {{ name }}!</h1>

html檔案 (等一下會介紹 不急)

@app.route('/add/<int:a>/<int:b>')
def add(a, b):
    return f'{a} + {b} = {a+b}'

http://127.0.0.1:8080/add/3/4

如何顯示前端

Flask

Flask

小補充:

如何將使用者導入其他網址

from flask import redirect, url_for

@app.route("/")
def main():
    return redirect(url_for("other_route"))
	#將使用者導到 /other_route 這個網址

Flask

實作一

/random/<int:min>/<int:max>

 

這個路由會在 min 和 max 之間產生一個隨機數並回傳,例如:

/random/1/100 → 隨機數:67

 

  • 提示:

import random

使用 random.randint(min, max)

Flask

from flask import Flask
import random

app = Flask(__name__)

@app.route('/random/<int:a>/<int:b>')
def main(a, b):
    return f'random number is {random.randint(a, b)}'

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

解答:

Jinja

Jinja

能把在後端把一些資訊傳給前端的東西

Jinja

{{ 兩個大括號是變數 }} 
	
{% 執行jinja2內置函數 %}
	
{# 註解說明 #}

語法:

在flask傳出變數,並顯示html:

from flask import render_template

name = "World"
return render_template("index.html", name=name)

Jinja

from flask import Flask
from flask import render_template

app = Flask(__name__)

@app.route("/")
def hello():
    name = "World"
    return render_template("index.html", name=name)

if __name__ == '__main__':
    app.run(debug=True,port=5000)
<h1>Hello {{ name }}!</h1>

html檔案

Flask

Jinja

from flask import Flask
from flask import render_template

app = Flask(__name__)

@app.route("/")
def main():
    name = "admin"
    return render_template("index.html", name=name)

if __name__ == '__main__':
    app.run(debug=True,port=5000)
    {% if name == "admin" %}
        <h1>Logged in, Hello {{ name }}!</h1>
    {% else %}
        <h1>Not Logged in, Try again!</h1>
    {%endif%}

Flask

html檔案

Jinja

from flask import Flask
from flask import render_template

app = Flask(__name__)

@app.route("/")
def main():
    items = ["apples", "bananas", "tomatoes"]
    return render_template("index.html", items=items)

if __name__ == '__main__':
    app.run(debug=True,port=5000)
    {% for item in items %}
        <li> {{ item }} </li>
    {% endfor %}

Flask

html檔案

Jinja

小補充:

如何在html導入css, js

(可以直接用url_for)

<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">

<script src="{{ url_for('static', filename='js/main.js') }}"></script>

Jinja

實作二

後端有一個數字陣列 arr

 

在前端迭代 arr

如果是偶數就用 <li> render那個數字出來

Jinja

解答:

from flask import Flask
from flask import render_template

app = Flask(__name__)

@app.route("/")
def main():
    arr = [1, 2, 5, 7, 3, 8, 10]
    return render_template(("index.html"), arr = arr)

if __name__ == '__main__':
    app.run(debug=True,port=5000)
    {% for i in arr %}
        {% if i%2 == 0 %}
            <li>{{ i }}</li>
        {% endif %}
    {% endfor %}

Flask

html檔案

HTTP Method

HTTP Method

假設今天我們要把一個東西從前端傳到後端

那我們要怎麼達到呢?

(沒是我只是想秀我setup和btr的東西)

資訊(如我空格輸入的東西)

他要這個資訊

HTTP Method

我們主要是用兩種方式

方法 get post
如何 直接加在URL後
head
傳送資料另外寫
body
好處 便宜 安全
壞處 不安全 貴
屬性 request.args request.form

沒有哪個一定比較好 要看情況

Get Method

我們該如何get到資訊呢?

直接加在URL後就好了!

http://127.0.0.1:5000/get_example?name=ming&email=ming@example.com

http://127.0.0.1:5000/get_example/ming/ming@example.com

 

都可以取得兩個資訊

那兩個有什麼區別呢?

Get Method

Query String (?a=5&b=10) Path Variables (/5/10)
傳遞方式 request.args.get() <int:a>、<int:b>
適合場景 搜尋、可選參數 固定結構的 API
URL 範例 /add?a=5&b=10 /add/5/10
可選參數 可以省略(使用 default) 不能省略,必須填值
可讀性 較靈活,適合不固定的查詢 較清楚,適合固定格式

假設我們要用get method拿到兩個數字

有兩種不同的方法

Form

通常來說都是用html中的<form>來傳送資訊

(你們昨天應該有學到table吧)

<h2>get method:</h2>
<form action="/get_example" method="get">
  <table border="1">
    <tr>
      <th>欄位</th>
      <th>輸入</th>
    </tr>
    <tr>
      <td>姓名</td>
      <td><input type="text" name="name"></td>
    </tr>
    <tr>
      <td>電子郵件</td>
      <td><input type="email" name="email"></td>
    </tr>
    <tr>
      <td colspan="2"><input type="submit" value="送出"></td>
    </tr>
  </table>
</form>

get:

後端找的內容

跟表單說這是get

Form

通常來說都是用html中的<form>來傳送資訊

(你們昨天應該有學到table吧)

<h2>post method</h2>
<form action="/post_example" method="post">
  <table border="1">
    <tr>
      <th>欄位</th>
      <th>輸入</th>
    </tr>
    <tr>
      <td>使用者名稱</td>
      <td><input type="text" name="username"></td>
    </tr>
    <tr>
      <td>密碼</td>
      <td><input type="password" name="password"></td>
    </tr>
    <tr>
      <td colspan="2"><input type="submit" value="提交"></td>
    </tr>
  </table>
</form>

post:

後端找的內容

跟表單說這是post

Form

get

from flask import Flask
from flask import redirect
from flask import request, render_template

app = Flask(__name__)

@app.route("/")
def main():
    return render_template("index.html")

@app.route("/get_example", methods=['GET']) #form把資訊傳到 "/get_example", 我們和flask說這是get method
def get_example():
    if request.args:
        #取得我們form的資料(在URL中)
        name = request.args.get('name')
        email = request.args.get('email')

        return f'<h2>{name} / {email} </h2>'
    else:
        return redirect("http://127.0.0.1:5000/") #如果沒收到,就回到主畫面

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

Form

get

可以看到 get的資訊都在URL裡面

Form

post

from flask import Flask
from flask import redirect
from flask import request, render_template

app = Flask(__name__)

@app.route("/")
def main():
    return render_template("index.html")

@app.route("/post_example", methods=['GET', 'POST']) #form把資訊傳到 "/post_example", 我們和flask說這是post method
def post_example():
    if request.method == 'POST':
        #取得我們form的資料
        name = request.form['username']
        email = request.form['password']

        return f'<h2>{name} / {email} </h2>'
    else:
        return redirect("http://127.0.0.1:5000/") #如果沒收到,就回到主畫面

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

Form

post

為什麼還要 'GET' 呢?

 

如果我們在沒有資料的情況下直接開啟網址

(例如直接打入網址,或把東西都寫在同個route底下)

 

那後端收到的第一次就會是 get method

而這樣才能正確的判斷 不出錯

HTTP Method

實作三

將剛剛講的表單輸入做出來

可以輸入你的名稱,email,密碼之類的東西

 

解答就是剛剛的扣(不要完全抄 自己寫寫看)

cookie/session

cookie?

cookie / session

http://127.0.0.1:5000/a

http://127.0.0.1:5000/b

架設我們今天要在route之間傳送資訊:

例如:登入狀態,偏好設定等

我們可以用cookie和session達到!

cookie

cookie是伺服器留給使用者的一些資訊

 

讓我們在載入其他route時,後端可以取來使用的資訊

cookie

怎麼知道這個cookie不是使用者自己簽的?

(不是伺服器給的)

加密 AES

數字簽名 RSA

session

在後端Flask存的Cookie

 

= session

經過簽名的cookie

session

Cookie Session
存在哪裡? 使用者
(Client 端)
伺服器
(Server 端)
安全性 不安全
容易被竊取、修改
安全
因為存放在伺服器
適用情境 記住登入狀態、偏好設定
(較不重要的東西)
會員登入、銀行交易
(需要更高安全性)

session

from flask import Flask, session

app = Flask(__name__)

secret_key = 'c4dffa417abe4d31936cdf52d3a6d7ae'
app.config['SECRET_KEY'] = secret_key #用來加密的

#有一個 session 的 dict,可以儲存一個使用者的資訊,並且在route之間溝通

@app.route('/login')
def login():
    session['login'] = True
    return 'Login success'

@app.route('/logout')
def logout():
    session['login'] = False
    return 'Logout success'
    
@app.route('/main')
def profile():
    if session.get('login'): #login
        return 'Main page'
    else: #not login
        return 'User not logged in'
    
if __name__ == '__main__':
    app.run(debug=True, port=5000)
# 生成一個隨機的 secret key
import uuid
print(uuid.uuid4().hex)

session

實作四

建立一個前端能輸入 使用者名稱跟密碼

他打什麼使用者名稱就把他存到 session 裡

 

並且做出一個admin介面

只有使用者名稱為admin和密碼符合才可查看

 

簡單來說就是建立一個簡單的登入頁面

session

解答

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h2>post method</h2>
    <form action="/post_example" method="post">
    <table border="1">
        <tr>
            <th>欄位</th>
            <th>輸入</th>
        </tr>
        <tr>
            <td>使用者名稱</td>
            <td><input type="text" name="username"></td>
        </tr>       
        <tr>
            <td>密碼</td>
            <td><input type="password" name="password"></td>
        </tr>
        <tr>
            <td colspan="2"><input type="submit" value="提交"></td>
        </tr>
    </table>
    </form>

</body>
</html>

session

解答

from flask import Flask
from flask import redirect
from flask import request, render_template, url_for, session

app = Flask(__name__)

secret_key = 'c4dffa417abe4d31936cdf52d3a6d7ae'
app.config['SECRET_KEY'] = secret_key #用來加密的

@app.route("/")
def main():
    return render_template("index.html")

@app.route("/post_example", methods=['GET', 'POST']) #form把資訊傳到 "/post_example", 我們和flask說這是post method
def post_example():
    if request.method == 'POST':
        #取得我們form的資料

        #把我們input的資料存到session
        session['name'] = request.form['username']
        session['password'] = request.form['password']

        #判斷我們的輸入是否正確
        if session['name'] == 'admin' and session['password'] == 'admin':
            return redirect(url_for('success'))
        else:
            return redirect(url_for('fail'))
    else:
        return redirect("http://127.0.0.1:5000/") #如果沒收到,就回到主畫面
    
@app.route("/success")
def success():
    #這裡用session,表示可以在路由之間傳送資訊
    return f"success! your name is {session['name']}, and your password is {session['password']}"

@app.route("/fail")
def fail():
    return f"login failed, please try again"

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

.env

.env

功能

讓重要或敏感資料(不能公開的)不顯示在程式碼上

如資料庫密碼、DcBot token

.env

2. 創建檔案:

一定要一模一樣

(對他是沒有名字的檔案 然後副檔名是 .env)

pip install python-dotenv

1. 下載python-dotenv:

.env

格式:

變數 = 值
變數 = "字串"

example:

secret_code = 67
password = "password"

.env

假設要丟到github上

那要怎麼隱藏env檔

1. 創建 .gitignore 檔 (對名字要一模一樣)

.env

如何使用

from flask import Flask

import os
from dotenv import load_dotenv
load_dotenv()

app = Flask(__name__)

@app.route("/")
def main():
    pw = os.getenv("password")
    return f'password is: {pw}'

if __name__ == '__main__':
    app.run(debug=True,port=5000)
password = "password"

.env

實作五

用 .env 檔存一個變數

在用flask把他顯示出來

 

(例如可以存存看剛剛的secret_key)

api

假設我們要從前端取後端的資訊,或是從其他伺服器拿資訊的化,我們要怎麼作呢?

(對我用了同張圖)

前端 (or 後端)

後端 (or 其他伺服器)

api

api

簡單來說,我們可以用api,從其他伺服器(或自己的)拿取資料

api

我們從自己的後端開一個api,然後再從前端的js拿取:

from flask import Flask, render_template, request, jsonify

app = Flask(__name__)

@app.route('/api_get', methods=['GET'])
def api_get():
    name = request.args.get('name')

    email = 'placeholder' #(可以從name拿一些資訊 啊我懶得做了 你們可以自己想想看)
    return jsonify({'message': f'Hello, {name}! Your Email is {email}.'})

@app.route('/')
def home():
    return render_template('index.html')
    
if __name__ == '__main__':
    app.run(debug=True, port=5000)

後端部分:

api

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Flask Class</title>
</head>
<body>
    <!--這裡可以有些輸入,像是要傳給後端的資料-->
    <input id="name">
    <button onclick="send_get_request()">click to get information!</button>
    <p id="response"></p>

    <script src="{{ url_for('static', filename='js/main.js') }}"></script>
</html>

前端部分:

function send_get_request(){
    //避免特殊字元(像是空格、&、=、/ 等)破壞網址格式。

    let name = document.getElementById("name").value;
    
    //encodeURIComponent() 是用來對使用者輸入的做 URL 編碼
    fetch(`/api_get?name=${encodeURIComponent(name)}`)
    .then(res => res.json()) //回應為 JSON
    .then(data => document.getElementById("response").innerText = data.message) //把那個資訊(data) 變成 #response 的文字
    .catch(err => console.error("錯誤:", err)); //如果錯誤的話
}

api

實作六

建立一個和剛剛類似,可以從前端輸入名字,

然後取得一些使用者資料的網站

 

(答案在上面,我懶得在用了 :P)

api

補充

在python 取得其他api的資訊

舉例來說:discord的api

每個api 通常來說都有 docs,

他會跟你說要輸入什麼,然後他會回傳什麼

api

import requests

API_ENDPOINT = "https://discord.com/api/v10"

def exchange_code(code):
    # gets the access_token

    data = {
        'grant_type': 'authorization_code',
        'code': code,
        'redirect_uri': redir
    }
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }

    r = requests.post(f'{API_ENDPOINT}/oauth2/token', data=data, headers=headers, auth=(client_id, client_secret))
    r.raise_for_status()
    return get_user_data(r.json()['access_token'])

def get_user_data(accessToken):
    # gets the user id from the access_token

    headers = {
        "Authorization": f"Bearer {accessToken}"
    }

    r = requests.get(url=api_url, headers=headers)
    r.raise_for_status()
    return r.json()

這兩個是dc bot的資訊

我們從這個api的網址request資訊

(開不懂沒關係 通常這種東西都用抄的)

websocket

websocket

client

server

ㄟ剛剛發生什麼事

可以跟我說嗎?

歐好啊 剛剛B說了這些話

那你可以幫我跟B說這些訊息嗎

websocket

websocket 讓在 client 和 server 間可以即時的溝通

websocket 協定只需連線一次,就能保持雙向溝通

不需重複發送 Request,因此回應更即時

進而提升 Web 通訊速度

websocket

emit 是傳送事件。

 

on 是監聽有無事件發生。

websocket

pip install flask-socketio
from flask import Flask, render_template
from flask_socketio import SocketIO, emit

app = Flask(__name__)
socketio = SocketIO(app)  # 初始化 SocketIO

@app.route('/')
def index():
    return render_template('index.html') 

# on 接收訊息
@socketio.on('chat message') 
def handle_message(msg):
    print(f'Received message: {msg}')
    emit('send', msg, broadcast=True)  # emit 給所有使用者

if __name__ == '__main__':
    socketio.run(app, port=5000, debug=True)  # 用 SocketIO 運行 Flask

websocket

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Flask Class</title>

    <script src="https://cdn.socket.io/4.8.3/socket.io.min.js"></script>
</head>

<body>
  <h1>聊天室</h1>
  <ul id="messages"></ul>
  <input id="input" placeholder="輸入訊息..." />
  <button onclick="sendMessage()">送出</button>

  <script src="{{ url_for('static', filename='js/main.js') }}"></script>
</body>

websocket

const socket = io(); // 初始化 socket 連線

socket.on('send', function(msg) {
    //將接收到的訊息存入一個list
    //並將這個東西append到 #messages 的child裡
    const li = document.createElement('li');
    li.textContent = msg;

    document.getElementById('messages').appendChild(li);
});

function sendMessage() {
    const input = document.getElementById('input');
    const msg = input.value;
    if (msg) {
        socket.emit('chat message', msg); //emit 給伺服器這個訊息
        input.value = '';
    }
}

websocket

實作七

製作一個進階的的聊天室

可以加入room和退出room

API 在下頁 讀讀看能不能看懂 :O

websocket

實作七

  • join_room(room):這個方法會讓當前用戶加入到指定的房間。當用戶加入房間後,該房間中的所有人可以接收到這個用戶加入的消息。

  • leave_room(room):這個方法會讓當前用戶離開指定的房間。當用戶離開房間後,其他房間中的用戶不會再接收到該用戶發送的消息。

  • emit('chat message', msg, room=room):這將消息廣播到指定的房間,而不是所有用戶。

 

API

 

下一頁有基礎版面

websocket

實作七

前端模版:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Socket.IO Flask Room Chat</title>

    <script src="https://cdn.socket.io/4.8.3/socket.io.min.js"></script>
</head>

<body>
    <h1>Socket.IO Flask Room Chat</h1>

    <ul id="messages"></ul>

    <input id="message" autocomplete="off" placeholder="Type a message">
    <button onclick="sendMessage()">Send</button><br>

    <input id="room" placeholder="Room name">
    <button onclick="joinRoom()">Join Room</button>
    <button onclick="leaveRoom()">Leave Room</button><br>

    <input id="username" placeholder="Username">

    <script src="{{ url_for('static', filename='js/main.js') }}"></script>
</body>

websocket

實作七

const socket = io(); // 初始化 socket 連線

socket.on('send', function(msg) {
    //將接收到的訊息存入一個list
    //並將這個東西append到 #messages 的child裡
    const li = document.createElement('li');
    li.textContent = msg;

    document.getElementById('messages').appendChild(li);
});

function sendMessage() {
    const msg = document.getElementById('message').value;
    const room_num = document.getElementById('room').value;
    const username = document.getElementById('username').value;
    if (msg) {
        socket.emit('chat', { msg: msg, room: room_num, username: username }); //emit 給伺服器這個訊息
        input.value = '';
    }
}

function joinRoom(){
    const room_num = document.getElementById('room').value;
    socket.emit('join', room_num)
}

function leaveRoom(){
    const room_num = document.getElementById('room').value;
    socket.emit('leave', room_num)
}

解答:

websocket

實作七

from flask import Flask, render_template
from flask_socketio import SocketIO, emit, join_room, leave_room, send

app = Flask(__name__)
socketio = SocketIO(app)  # 初始化 SocketIO

@app.route('/')
def index():
    return render_template('index.html') 

# on 接收訊息
@socketio.on('chat') 
def handle_message(data):
    msg = data['msg']
    room = data['room']
    username = data['username']
    msg = username + ": " + msg

    print(f'Received message: {msg}')
    emit('send', msg, room=room)  # emit 給所有使用者

# join room
@socketio.on('join')
def on_join(room):
    print(f'Joined room {room}')
    join_room(room)

# leave room
@socketio.on('leave')
def on_leave(room):
    print(f'Left room {room}')
    leave_room(room)

if __name__ == '__main__':
    socketio.run(app, port=5000, debug=True)  # 用 SocketIO 運行 Flask

解答:

websocket

實作七

想想看

我們要如何每個房間分別不同的聊天室?或是怎麼限制使用者只能在一個房間中

課程結束

幾樣我沒講到

但其實也算重要的東西:

Data Base

blueprint

祝你們寫後端好運!

Flask

By MLGnotCOOL