# 07/26課堂筆記
###### tags: `學長作業` `flask` `python`
## 練習準備
電腦要有[PostMan](https://www.postman.com/)和安裝好虛擬環境的專案目錄![](https://i.imgur.com/E2X59sR.png =70%x)
app.py內我們先寫一個最基礎flask架構
```python
from flask import Flask, render_template
app = Flask(__name__)
# 啟用Debug
app.config['ENV'] = "development"
app.config['Debug'] = True
@app.route("/") # 啟用路徑'/'
def home():
return render_template("index.html")
# 啟動Server
app.run()
```
我們在專案目錄內的templates目錄新增一個index.html檔案
```htmlembedded
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>主畫面</title>
<h1>我是主畫面</h1>
</head>
<body>
</body>
</html>
```
## 1. json 資料傳遞
### python code解釋與呈現
在app.py新增一段程式新增`request`物件
>![](https://i.imgur.com/aFl41g8.png)
在後面新增一個`/test5`的路徑
```python
@app.route("/test5", methods=["POST"]) # 新增一個可以傳遞Json格式的路徑
def jsonValue():
if request.is_json: # 判斷是否為JSON #判斷方式是根據 HTTP Header 的 Connect-Type有無application/json
data = request.get_json()
result = data.get('name', None)
result = data.get('sex', None)
result = data.get('ID', None)
print(data)
else:
result = 'NO JSON Data'
return result
```
### Postman 操作
之後我們打開Postman按照下圖流程
1. 點擊Collections
2. 點選網址輸入欄旁的傳輸方法,這裡我們選POST
3. 輸入我們的網址路徑,我們這裡是用test5
4. 我們點選Body
5. 選擇Body底下的raw
6. 輸入格式我們選擇JSON
7. 輸入JSON格式的資料,資料的Key要對應到/test5的Key
8. 送出
* 操作如下 :arrow_down:
>![](https://i.imgur.com/ZbH04Uz.png)
我們看一下結果(補充: python flask return 的格式只能是字串,所以把數字的雙引號拿掉就會出錯)
>![](https://i.imgur.com/n7IK7Yl.png)
看一下我們剛剛使用`print(data)`的結果 :arrow_down:
>![](https://i.imgur.com/fEe5hAB.png)
我們回到Postman,我們可以查看header的content-Type這裡會存我們傳送出去的資料格式
>![](https://i.imgur.com/VpmSFfU.png)
## 2. 檔案上傳
### python code解釋與呈現
我們需要再`import`新的物件 :arrow_down:
>![](https://i.imgur.com/iIUeYSN.png)
>
>![](https://i.imgur.com/8qQnqwU.png)
增加新的路徑 `/file-upload` :arrow_down:
```python
@app.route("/file-upload", methods=["POST"])
def upload():
f = request.files['upload_img'] # 設定上傳檔案名稱
filename = secure_filename(f.filename)
os.makedirs("./upload", exist_ok=True) # 確定會有upload目錄,沒有的話會自行創建
f.save(os.path.join("./upload", filename))
return "success"
```
### Postman 操作
1. 我們輸入我們可以上傳檔案的網址路徑
2. 點選Body
3. 選擇form-data
4. 輸入與python對應的key名稱
5. 選擇上傳格式
6. 選擇File
7. 選擇要上傳的檔案
8. 送出
* 成功在Postman會看到Success
* Vscode 會看到upload目錄以及我們上傳的圖檔
>![](https://i.imgur.com/8ds3HpV.png)
>![](https://i.imgur.com/yL5kN6y.png)
## 3.Flask 回傳參數 - HTML Escape
避免有心人士利用[XSS攻擊](https://medium.com/hannah-lin/%E5%BE%9E%E6%94%BB%E6%93%8A%E8%87%AA%E5%B7%B1%E7%B6%B2%E7%AB%99%E5%AD%B8-xss-cross-site-scripting-%E5%8E%9F%E7%90%86%E7%AF%87-fec3d1864e42)網站
### XSS演示
先新增一個有query String的路徑
```python
@app.route("/test01")
def test1():
ans = request.args.get("input", "hello")
return "ans is "+ans
```
>![](https://i.imgur.com/30BuCZ6.png)
如果我在網址打 ?input=`<script>alert('XSS test')</script>`會出現下面這種狀況,如果更嚴重可能會影響到整個網站的運作
>![](https://i.imgur.com/e5hOX0W.png)
所以我們需要學習使用HTML_Escape
### python code解釋與呈現
我們需要導入新的物件
>![](https://i.imgur.com/zepf8Kv.png)
我們在用escape把原本的code包起來
>![](https://i.imgur.com/OyHMPOO.png)
我們看一下結果:
![](https://i.imgur.com/Gz9Xt11.png)
如此一來可以簡單地避免掉一些有心人士的攻擊
## 4.Flask 回傳參數 - JSON
我們可以利用json.dumps()達成
### python code解釋與呈現
import JSON套件
![](https://i.imgur.com/3rANvW8.png)
再新增一個路徑`/return_json`
```python
@app.route("/return_json", methods=["POST"])
def retrun_json():
# 創建一個字典dict
dict = {
"name": "chichi",
"sex": "male",
"ID": 12345678
}
return json.dumps(dict)
```
我們會看到下圖結果醜醜的,而且被包成HTML
>![](https://i.imgur.com/voCgmR5.png)
>-
>![](https://i.imgur.com/yK3e9gG.png)
那我們改成利用Flask內建的直接回傳字典,`return json.dumps(dict)`改為`return dict`,我們看看結果
>![](https://i.imgur.com/xdH4fjc.png)
>![](https://i.imgur.com/KSKPbDg.png)
所以json.dumps()是將字典轉為字串~!而你直接回傳dictonary Flask會幫你改為字串!!
### 5.補充字串改JSON
可以利用flask的jsonfy
>![](https://i.imgur.com/DqUdYDg.png)
用jsonify將字串包起來
>![](https://i.imgur.com/WQpHrLi.png)
看一下結果:
>![](https://i.imgur.com/Y25lqAv.png)
>-
>![](https://i.imgur.com/c90CS9h.png)
## 之後可以補充一下 RESTful
## Flask cookie
紀錄一些不重要的數據,紀錄在前端使用者也可以查閱
### python code解釋與呈現
我們需要導入make_reaponse物件
>![](https://i.imgur.com/ufIw1sm.png)
新增一個login路徑
>![](https://i.imgur.com/btYHyxC.png)
我們執行看看:
>![](https://i.imgur.com/bHGNLP8.png =80%x)
>--
>![](https://i.imgur.com/kRvFb7B.png =80%x)
## session
1. 開一個flask的基本程式,並創建一個/hello路徑
>![](https://i.imgur.com/PadYQ9X.png)
2. 我們看一下Server,good~ 有互動~
>![](https://i.imgur.com/O4SXfaB.png)
3. 再創建一個`/talk`路徑,疑??要怎麼記住name?
>![](https://i.imgur.com/hK4KaCC.png)
4. 我們要載入session工具
>![](https://i.imgur.com/cPHMHj9.png)
5. 我們要設定密鑰
>![](https://i.imgur.com/V0PfP9R.png)
6. 我們要寫的應用,再`/hello`中存放我們得到的值
>![](https://i.imgur.com/vt4dPUK.png)
7. 解惑搂~我們在`/talk`中使用我們記住的`username`
>![](https://i.imgur.com/LwksETI.png)
### 結果展示
![](https://i.imgur.com/lQYbKM6.png)
直接進入`/talk`...你看成功了~
![](https://i.imgur.com/Ef94rBS.png)
## 我的code
Templates -> index.html
```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>主畫面</title>
<h1>我是主畫面</h1>
</head>
<body>
<form method="post" action="/login">
名字 : <input type="text" name="name">
<button>確定</button>
</form>
</body>
</html>
```
Templates -> page.html
```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>這是分頁</title>
</head>
<body>
<h1>我是 {{ nameis }}</h1>
</body>
</html>
```
app.py
```
from flask import Flask, redirect, render_template, request, jsonify, make_response, template_rendered, url_for
from flask import Response, url_for, session
from werkzeug.utils import secure_filename
import os
from markupsafe import escape
import json
app = Flask(__name__)
app.secret_key = "chichi"
# 啟用Debug
app.config['ENV'] = "development"
app.config['DEBUG'] = True
@app.route("/") # 啟用路徑'/'
def index():
return render_template("index.html")
@app.route("/test5", methods=["POST"]) # 新增一個可以傳遞Json格式的路徑
def jsonValue():
if request.is_json: # 判斷是否為JSON #判斷方式是根據 HTTP Header 的 Connect-Type有無application/json
data = request.get_json()
result = data.get('name', None)
result = data.get('sex', None)
result = data.get('ID', None)
print(data)
else:
result = 'NO JSON Data'
return result
@app.route("/file-upload", methods=["POST"])
def upload():
f = request.files['upload_img'] # 設定上傳檔案名稱
filename = secure_filename(f.filename)
os.makedirs("./upload", exist_ok=True) # 確定會有upload目錄,沒有的話會自行創建
f.save(os.path.join("./upload", filename))
return "success"
# XSS TEST
@app.route("/test01")
def test1():
ans = escape(request.args.get("input", "hello"))
return "ans is "+ans
@app.route("/return_json", methods=["POST"])
def retrun_json():
# 創建一個字典dict
dict = {
"name": "chichi",
"sex": "male",
"ID": 12345678
}
return dict
@app.route("/jsonify", methods=["POST"])
def retrun_jsonify():
# 創建一個字典dict
str1 = "I am String"
return jsonify(str1)
@app.route("/login", methods=["post", "GET"])
def login():
account = request.values.get('name', "chichi")
response = make_response(render_template('index.html'))
response.set_cookie('username', account)
session['user'] = account
return response
@app.route('/session')
def session_text():
name = session['user']
render_template("page.html", nameis=name)
return render_template("page.html", nameis=name)
# 啟動Server
app.run()
```