---
# System prepended metadata

title: 07/26課堂筆記
tags: [flask, 學長作業, python]

---

# 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()

```
