後端框架flask學習小記

2021-12-09 22:00:02

1. 寫在前面

最近在和幾個夥伴嘗試搭建一個新聞推薦系統, 算是一個推薦演演算法的實戰專案, 裡面涉及到了前後端互動, 該專案裡面,使用了Flask作為後臺框架, 為了理清楚整個系統的互動,所以就快速參考著資料學習了下flask, 主要還是參考夥伴們寫的flask簡介和基礎的內容, 加上了一些其他理解和實驗輔助, 整理一篇心得文章, 算是flask初步入門。

對於一個演演算法工程師來講,後端這塊雖然不必詳細弄清楚原理,但學習一些開發相關知識還是有好處的,因為在實際工作中經常會偵錯線上的程式碼呼叫策略或者模型,我們至少得弄明白,我們的資料流, 模型流到底是怎麼走的, 整個系統從輸入到最終輸出是怎麼執行的,這樣才能運籌帷幄,從一個更高的角度去看待問題。

好吧,有點扯遠了, 本篇文章主要介紹flask,這裡依然是從使用的角度整理(因為我對原理也不清楚哈哈), 先不管那麼多,會用就行, flask簡單的來講, 就是一個後端框架,基於python語言編寫,比較容易上手,或者說不用懂太多細節就能寫程式碼, 把前端傳過來的請求,通過編寫一些函數進行處理,然後返回給前端。 這裡為了更好的理解,我會用一個非常簡單的例子貫穿整個流程。 當然,如果想看稍微高大上點的程式碼,也可以去我們寫的fun-rec專案,看新聞推薦系統的程式碼, 那個是vue-flask互動配合的,更加高階些。

所以,最簡單的整個流程就是, 我們在前端頁面上輸入資訊,傳送請求給後端(flask), flask根據我們傳過來的請求,去找到相應的函數去處理我們的請求(路由), 然後函數處理的結果封裝起來返回給前端展示。 這次,主要是看看請求傳過來之後,後端這個怎麼找函數處理以及返回回去。

主要內容:

  • 先設定環境,安裝flask
  • 路由 - 去找函數處理請求
  • 請求、響應和對談
  • 重定向與錯誤處理
  • 前端簡單製作form表單 - 準備互動
  • 介紹兩款工具(資料庫操作API(sqlarchemy)和介面測試工具(Postman))
  • 小例子打通前後端互動流程
  • 新聞推薦系統vue和flask是怎麼聯絡起來的呢?

Ok, let’s go!

2. 先設定環境,安裝flask

這個不用多整理, flask在python裡面也是一個包的形式存在,所以我們如果事先安裝好了anaconda, 建立了虛擬環境,那麼就直接可以

pip install flask

然後輸入下面程式碼測試下:

from flask import Flask
app = Flask(__name__)

@app.route('/')   # 這個根目錄,就是127.0.0.1:5000進入的位置
def hello_world():
	return "hello world"

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

如果正常的話,介面會顯示hello world。其實,這就簡單的走了一遍小流程(輸入網址,根據路由到了hello_word函數,返回結果給前端)。

Flask將(name)作為引數,即Flask在當前模組執行,route()函數是一個裝飾器,將請求的url對映到對應的函數上。上述程式碼將’/'與hello_world()函數進行繫結,因此在請求localhost:5000時,網頁顯示 Hello World 結果。

這裡有幾個關鍵點: 導包, 建立app(Flask(__name__)),路由匹配(@app.route())以及啟動(app.run())。 幾乎在寫每個後端處理之前,這幾個先寫上再說。

程式的啟動是用過Flask類的run()方法在本地啟動伺服器應用程式

app.run(host, port, debug, options)

# 允許伺服器被公開存取
app.run(debug=True, host='0.0.0.0', port=3000, threaded=True)
# 只能被自己的機子存取
# app.run(debug=True, host='127.0.0.1', port=10086, threaded=True)

這幾個引數的描述如下:
在這裡插入圖片描述
安裝這塊比較簡單,先這樣。

3. 路由 - 去找函數處理請求

web介面輸入一個網址,點選回車, 其實是存取的web伺服器,然後伺服器把結果返回到前端。 這個過程中有個匹配url的過程, 就是flask路由。

Flask中,路由是指使用者請求的URL與檢視函數之間的對映。Flask通過利用路由表將URL對映到對應的檢視函數,根據檢視函數的執行結果返回給WSGI伺服器。

路由表的內容是由開發者進行填充, 主要有以下兩個方式:

  • route裝飾器: 使用Flask應用範例的route裝飾器,將一個URL規則繫結到一個檢視函數上

    # 通過裝飾器的方式, Flask框架會將URL規則繫結到test()函數上, 這個很好用
    @app.route('/test')       # 瀏覽器存取的時候,輸入的url是127.0.0.1/test
    def test():
    	return 'this is response of test function'
    
  • add_url_rule() :該方法直接會在路由表中註冊對映關係。其實route裝飾器內部也是通過呼叫add_url_rule()方法實現的路由註冊

    def test():
      return 'this is response of test function.'
    app.add_url_rule('/test',view_func=test)
    

我習慣看第一種方式, 感覺比較帥。

3.1 指定HTTP方法

預設情況下, Flask的路由支援HTTP的GET請求, 如果需要試圖函數支援HTTP的其他方法, 可以通過methods關鍵字引數進行設定。 關鍵字引數methods的型別為list, 可以同時指定多種HTTP方法。

# 接收post和get請求, 如果不指定的話,就是get請求, 此時如果提交post請求是捕捉不到的
@app.route('/user', methods = ['POST', 'GET'])   
def get_users():
  if request.method == 'GET':
    return ... # 返回使用者列表
  else:
    return ... # 建立新使用者

這裡先說下這兩種請求的區別:

  • GET把引數包含在URL中, 也就是直接輸入網址存取, 把引數放到這個網址裡面去的時候,存取的就是get請求
  • POST通過request body傳遞引數, 採用表單的時候往往就是這個。 關於這個,後面測試介面的時候,會通過Postman進行演示。

這樣就完成了最基本的功能, 當然,你說, 這個URL(/user)是寫死的目前,如果我不確定怎麼辦呢? 比如, 我可能這個使用者是某某, 而不同的某某,可能有不同的執行操作,這時候,就可以使用動態URL。

3.2 動態URL

動態URL用於當需要將同一類URL對映到同一個檢視函數處理,比如,使用同一個檢視函數 來顯示不同使用者的個人資訊。那麼可以將URL中的可變部分使用一對小括號<>宣告為變數, 併為檢視函數宣告同名的引數:

@app.route('/user/<uname>')   # <>提取引數用的
def get_userInfo(uname):
  return '%s\'s Informations' % uname


# 輸入網址127.0.0.1/user/wuzhongqiang     wuzhongqiang's Informations
# 輸入網址127.0.0.1/user/zhangsan       zhangsan's Informations

除了上述方式來設定引數,還可以在URL引數前新增轉換器來轉換引數型別: 前端本身預設是傳入過來的是字串格式,如果感覺本身傳入的引數不應該是字串格式的,那就可以在URL引數前新增轉換器轉換引數型別

@app.route('/user/<int:uname>')   # <int: name>  int 是一個轉換器
def get_userInfo(uname):
    return '%s\'s Informations' % uname

使用該方法時,請求的引數必須是屬於int型別,否則將會出現404錯誤。目前支援的引數型別轉換器有int, float, string, path。後兩者的區別是path裡面可以有\

為了滿足一個檢視函數可以解決多個問題,因此每個檢視函數可以設定多個路由規則

@app.route('/user')
@app.route('/user/<uname>')
@app.route('/user/<int:uname>')
def get_userInfo(uname=None):
    if uname:
    	return '%s\'s Informations' % uname
    else:
        return 'this is all informations of users'

3.3 自定義匹配規則

當然,這裡也可以自定義一些規則,去進行輸入方面的一些限制, 這時候,就需要繼承BaseConverter類,然後寫自己的規則了。 這裡只是舉個簡單的例子:

from flask import Flask
from werkzeug.routing import BaseConverter

app = Flask(__name__)

class RegexConverter(BaseConverter):
    """自定義轉化器類"""
    def __init__(self, url_map, regex):
        super(RegexConverter, self).__init__(url_map)
        self.regex = regex

    def to_python(self, value: str):
        return value

# 將自定義的轉換器類新增到flask應用中
app.url_map.converters['re'] = RegexConverter

@app.route('/index/<re("1\d{5}"):value>')   
def index(value):
    return "hello, world"

app.run()

# 只有如輸入 127.0.0.1/index/123456    1開頭,後面5位整數的才能匹配到

這個裡面的匹配URL就可以使用正則的形式,匹配非常特殊的那種了。不過,一般用不到這麼複雜的。

3.3 URL構建方法

在很多時候,在一個實用的檢視中需要指向其他檢視的連線,為了防止路徑出現問題,我們可以讓Flask框架幫我們計算連結URL。簡單地給url_for()函數傳入一個存取點,它返回將是一個可靠的URL地址

@app.route('/')
def hello():
    return 'Hello world!'
    
@app.route('/test')
def test_url_for():
    print(url_for('hello'))  # 跳轉到了hello函數下面執行

4. 請求、響應和對談

對於一個完整的HTTP請求,包括了來自使用者端的請求物件(Request), 伺服器端的響應物件(Respose)和對談物件(Session)等。 在Flask框架中,當然也具有這些物件, 這些物件不僅可以在請求函數中使用, 同時也可以在模板中使用。

4.1 請求物件Request

Flask包中, 可以直接引入request物件, 其中包含Form,args,Cookies,files等屬性。

  • Form: 字典物件, 包含表單當中所有引數及值的鍵和值對
  • args: 解析字串的內容, 是問號?之後的URL的一部分, 當使用get請求時, 通過URL傳遞引數時可以通過args屬性獲取
  • cookies: 用來儲存cookie名稱和值的字典物件
  • files: 屬性和上傳檔案有關的資料

以一個登陸的例子看看如何搭配屬性

from flask import request, session, make_response

@app.route('/login', methods=['POST', 'GET'])
def logion():
	if request.method == 'POST':
		if request.form['username'] == 'admin':
			session['username'] = request.form['username']
			response = make_response('Admin login successfully!')
			response.set_cookie('login_time', time.strftime('%Y-%m-%d' %H:%M:%S'))
			return 'Admin login successfully!'
	elif request.method == 'GET':
		if request.args.get("username") == 'admin':
            session['username'] = request.form['username']
            return 'Admin login successfully!'
    else:
            return 'No such user!'

app.secret_key = '123456'

可以根據method屬性判斷當前請求的型別,通過form屬性可以獲取表單資訊,並通過session來儲存使用者登陸資訊。當然這裡的session,可以換成字典,然後把資訊儲存到資料庫裡面去。

由於現在前後端互動會採用json的資料格式進行傳輸, 因此當前端請求的資料是json型別的時候, 可以使用get_data()方法來獲取。

from flask import Flask, jsonify, request
@app.route('/login', methods=["POST"])
def login():
    request_str = request.get_data()
    request_dict = json.loads(request_str)
    # 然後,就可以對request_dict進行處理了,相當於從後端拿到了前端的資料

4.2 響應物件response

如果函數試圖想向前端返回資料, 必須是Response物件,主要有下面幾種返回資料的格式:

  1. 試圖函數return多個值

    @app.route("/user_one")
    def user_one():
        return "userInfo.html", "200 Ok", {"name": "zhangsan"; "age":"20"}
    

    當return多個值的時候,第一個是字串,也是網頁的內容;"200 Ok"表示狀態碼及解析;{「name」: 「zhangsan」; 「age」:「20」} 表示請求頭。其中前面兩個值是必須要的並且順序不能改變,請求頭不是必須要的,這樣Flask會自動將返回的值轉換成一個相應物件。如果返回一個字串,則Response將該字串作為主體,狀態碼為200,然後返回該Response物件。

  2. 使用Response建立
    可以通過直接建立Response物件,設定其引數。

    from flask import Response
    
    @app.route("/user_one")
    def user_one():
        response = Response("user_one")
        response.status_code = 200
        response.status = "200 ok"
        response.data = {"name": "zhangsan"; "age":"20"}
        return response
    

    由於現在前後端互動往往採用的是json的資料格式,因此可以將資料通過 jsonify 函數將其轉化成json格式,再通過response物件傳送給前端。

    # 這個jsonify可以直接向前端返回json資料
    from flask import Flask, make_response, jsonify   
    
    @app.route('/hot_list', methods=["GET"])
    def hot_list():
        if request.method == "GET":
            user_id = request.args.get('user_id')
            page_id = request.args.get('page_id')
            if user_id is None or page_id is None:
                return make_response(jsonify({"code": 2000, "msg": "user_id or page_id is none!"}), 200)
    				try:
    		        rec_news_list = recsys_server.get_rec_list(user_id, page_id)
    		        if len(rec_news_list) == 0:
    		            return jsonify({"code": 500, "msg": "rec_list data is empty."})
    		        return jsonify({"code": 200, "msg": "request rec_list success.", "data": rec_news_list, "user_id": user_id})  # 後面的資料就能返回到前端去
    		    except Exception as e:
    		        print(str(e))
    		        return jsonify({"code": 500, "msg": "redis fail."})
    

    前端拿到這個data,和user_id,就可以通過變數的方式進行使用了。這種方式用的多一些。

當然,這些東西直接這麼寫,可能會很抽象,後面一個小例子一串就瞭然, 這裡可以先有個印象。

5. 重定向與錯誤處理

5.1 重定向

當一個請求過來後可能還需要請求另一個檢視函數才能達到目的, 就可以呼叫redirect(location, code=302, Response=None)函數指定重定向頁面。

from flask import Flask, redirect, url_for

app = Flask(__name__)

@app.route("/demo")
def demo():
    url = url_for("demo2")  # 路由反轉,根據檢視函數名獲取路由地址
    return redirect(url)   # 相當於到了/demo2這個頁面,顯式this is demo2 page

@app.route("/demo2")
def demo2():
    return "this is demo2 page"

@app.route("/")
def index():
    # 使用方法:redirect(location, code=302, Response=None) 
    return redirect("/demo", 301)

url_for函數我理解是能根據給定的url對映到對應的函數,比如給定demo2, 就對映到了demo2(), 但具體執行, 應該是redirect()函數起作用。

5.2 錯誤處理

當請求或伺服器出現錯誤的時候, 我們希望遇到特定錯誤程式碼走不通的處理錯誤邏輯, 可以使用errorhandler()裝飾器

from flask import render_template   # 渲染頁面

@app.errorhandler(404)
def page_not_found(error):
    return render_template('page_not_found.html'), 404

當遇到404錯誤時,會呼叫page_not_found()函數,返回元組資料,第一個元素是」page_not_found.html」的模板頁,第二個元素代表錯誤程式碼,返回值會自動轉成 response 物件。 如果這個地方想在網頁裡面放張圖片的話,一定要放到static目錄裡面才行, 存取的是靜態檔案目錄, 這個static名字不能改。

這個東西主要是為了後面處理異常,如果滿足什麼條件,就進行什麼樣的處理:

from flask import abort
@app.route('/index', methods=['GET', 'POST'])
def index():
		if request.method == 'GET':
				return render_template('index.html')
		if request.method == 'POST':
				name = request.form.get('name')
				password = request.form.get('password')
				if name == 'zhangsan' and password == '123':
								return 'login success'
				else:
								abort(404)
								return None

6. 構建form表單,為互動做準備

上面整理了那麼一大推, 這裡想通過一個例子串一下, 否則總會有一股朦朧之感, 由於我不是很懂前端, 這裡就簡單參考程式碼寫一個前端頁面, 不用很複雜,就構建一個輸入使用者名稱和密碼的對話方塊,然後點選提交,看看與後端的互動效果。

前端頁面的程式碼如下:
在這裡插入圖片描述
這個佈局方式也是蠻重要的, 就是先建立一個templates目錄,這個目錄可以認為是有一個模板目錄,預設定義了一些前後端互動的程式碼格式。這個模板是jinjia2(右擊目錄,mark directory as設定), 然後在該目錄下建立一個HTML介面。

然後在上一級目錄,建立一個form表單檔案,把這個HTML渲染出來:

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/index')
def index():
    return render_template('index.html')  # 渲染當前的html頁面

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

# 輸入127.0.0.1:5000/index  就會出來寫的那個html頁面了,然後輸入密碼,提交,就會得到一個get請求

此時,就能把前端的html頁面顯示出來。
在這裡插入圖片描述
當然,比較陋, 但演示足夠。下面看看如何互動。

7. 前後端互動小例子

這裡前端,從上面的兩個框裡輸入使用者名稱和密碼,然後點選提交給後端。 後端接收過來, 把使用者和密碼封裝起來, 給到另一個前端頁面, 然後另一個前端頁面就能用這個資料了。

首先, 需要先修改上面前端頁面資料, 把提交請求的方式改為POST,非常簡單, 只需要修改這裡。
在這裡插入圖片描述
然後在總目錄下建立了request物件.py檔案,在這裡面寫接收資料的邏輯

from flask import Flask, render_template
from flask import request

app = Flask(__name__)

@app.route('/index', methods=['GET', 'POST'])
def index():
    if request.method == 'GET':
        # 渲染index頁面
        return render_template('index.html')
    elif request.method == 'POST':
        # 獲取資料
        data = {}
        data['name'] = request.args.get('name')   # 後面這個name和前端的name保持一致
        data['passwd'] = request.args.get('password')

        # 返回到前端去
        return render_template('index2.html', data=data)

    return render_template('index.html')

app.run()

其實也非常簡單,輸入網址的時候,顯式的就是index.html頁面,這個頁面就是讓使用者輸入使用者名稱密碼,然後提交即可,此時由於修改了index的提交方式是post請求,所以後端這塊捕捉到,拿到傳過來的資料, 給到index2.html, 此時index2.html就可以直接拿到data使用或者用來展示。

index2.html頁面此時就能使用data資料了。
在這裡插入圖片描述
框裡的這兩個,就是index.html傳給後端,然後後端傳過來的資料, 可以直接在index2.html中顯示。 當然,這裡的{{變數名}}的這種定義格式,就是模板事先定義好的,如果不是jinjia2模板,可能不能使用。所謂模板,就是事先定義了一些前後端互動的規則。

上面就是一個前後端互動的小例子啦, 其實flask框架用起來還是比較容易上手的。

8. 介紹兩款工具

這裡主要是介紹這兩天用到的兩個工具,SQLAlchemy和Postman。

8.1 SQLAlchemy

這是一個功能強大的python ORM工具包, 也就是提供了API去運算元據庫裡面的表的相關操作,而不是編寫原始的SQL語句,非常方便。安裝

# 安裝
pip install SQLalchemy

8.1.1 連線資料庫

下面建立連線,也就是連線到我們的mysql資料庫:

from sqlalchemy import create_engine

def mysql_db(host='127.0.0.1', dbname='3306'):
	engine = create_engine("mysql+pymysql://root:123456@{}:49168/{}?charset=utf8".formate(host, dbname))
	print(engine) # Engine(mysql+pymysql://root:***@127.0.0.1:49168/3306?charset=utf8)

通過create_engine函數已經建立了Engine,在Engine內部實際上會建立一個Pool(連線池)和Dialect(方言),並且可以發現此時Engine並不會建立連線,只會等到執行到具體的語句時才會連線到資料庫。上述程式碼預設本地已經存在並開啟mysql服務。

create_engine("mysql://user:password@hostname/dbname?charset=utf8",
                       echo=True,
                       pool_size=8,
                       pool_recycle=60*30)

第一個引數是和框架表明連線資料庫所需的資訊,「資料庫+資料庫連線框架://使用者名稱:密碼@IP地址:埠號/資料庫名稱?連線引數」;echo是設定當前ORM語句是否轉化為SQL列印;pool_size是用來設定連線池大小,預設值為5;pool_recycle設定連線失效的時間,超過時間連線池會自動斷開。

8.1.2 建立資料庫表類

用於SQLAlchemy是物件關係對映,在運算元據庫表時是通過操作物件實現的, 每一條記錄其實是一個物件,所以需要先建立一個資料庫表類說明欄位資訊。

from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):
	__tablename__ = 'UserInfo'  # 表名
	# 資料庫欄位的型別
	index = Column(Integer(), primary_key=True)
	user_id = Column(Integer(), unique=True)
	username = Column(String(30))
	passwd = Column(String(500))

	def __init__(self, index, user_id, username, passwd):
		self.index = index
		self.user_id = user_id
		self.username = username
		self.paswd = passwd

這個可以當做是固定套路格式, 通過declarative_base()函數,可以將python類和資料庫表進行關聯對映,並通過 _tablename_ 屬性將資料庫模型類和表進行管理。其中Column() 表示資料表中的列,Integer()String()表示資料庫的資料型別。

8.1.3 運算元據庫

建立完連線, 需要藉助sqlarchemy中的session來建立程式與資料庫之間的對談,此時通過sessionmarker()函數建立。

def mysql_db(host='127.0.0.1', dbname='test'):
	engine = create("mysql+pymysql://root:123456@{}:49168/{}?charset=utf8mb4".format(host,dbname))
	
	session = sessionmaker(bind=engine)
	Base.metadata.create_all(engine)
	return engine, session()

這樣,相當於正式與mysql建立了連線時候的對談。 session常用的方法:

  • flush: 預提交,提交到資料庫檔案,此時還未寫入資料庫檔案中
  • commit: 提交了一個事務
  • rollback: 回滾
  • close: 關閉session連線

下面演示下資料庫裡面的增刪改查。

  1. 增加資料

    # 增加一個使用者
    engine, session = mysql_db()
    
    user = User("100", "zhangsan", "11111")
    session.add(user)
    session.commit()
    
    # 也可以通過addall批次提交
    engine, session = mysql_db()
    user1 = User("101","lisi","11111")
    user2 = User("102","wangwu","22222")
    session.add_all([user1,user2])
    session.commit()
    

    不用我們事先建立資料庫和表, 呼叫程式的時候,會自動建立好。 把使用者的資訊封裝成一個物件,然後採用add的方式就可以新增進去了。 當然session.add()不會直接提交到資料庫,當執行了commit()之後才會提交。 這時候,就不用什麼insert table_name values …。

    注意,如果是python的datetime格式資料,是無法直接存到mysql時間格式裡面的, 必須強轉成字串才能存進去, 這也是實踐中遇到的一個坑。

  2. 查詢資料

    engine, session = mysql_db()
    users = session.query(User).filter_by(passwd='11111').all()
    
    for item in users:
        print(item.username,item.passwd)
    

    通過上面程式碼就可以存取資料庫, 類似於select操作了, 其中query()返回一個query物件,在這裡指明查哪個大類(這裡面對映一個資料表),告訴去哪個表裡查。 當然此時並沒有真正去查詢, 只有等到具體執行函數count(), first(), all()等採取資料庫查詢。 當然,還可以使用filter()方法指定查詢條件,類似where。 這裡其實有兩種寫法:

    • filter_by(passwd=''11111")過濾
    • filter(User.passwd="11111")過濾 , 這一種需要帶上類名
  3. 修改資料

    session.query(User).filter_by(username="zhangsan").update({'passwd': "123456"})
    

    update()函數進行修改。

  4. 刪除資料

    session.query(User).filter(User.username == "zhangsan-test").delete()
    session.commit()
    

8.2 Postman

當然這個東西由於也是剛接觸,並不是太會用。 這個東西是有個介面測試工具, 是為了驗證後端開發的介面是否可用。

因為真正開發大專案,前後端是分離開發的, 並且此時前端可能沒有完全搭建好,所以介面測試的時候,postman,就相當於一個使用者端, 可以模擬使用者發起各類的HTTP請求, 將請求資料傳送給伺服器端, 來獲取對應的響應結果。 這樣就能測試出後端的函數邏輯是否正確。

我這裡是偶然接觸到,因為學習上面新聞推薦系統的時候,我這邊後端的每個py檔案都執行通過了,此時想基於介面傳資料看看效果,結果就是和前端的vue框架連不起來。 上面我自己寫HTML檔案好好的, 一旦用上vue框架,再去存取網址總是報錯或者被拒絕啥的。

所以,這裡就想看看到底是後端給的網址和介面不對,還是前端vue的問題,那麼怎麼測試呢? 意哥就告訴了我這個工具,用他來模擬前端,給後端發請求,看看後端能返回結果不。

當然具體的下載和使用, 我給出兩篇參考檔案postman教學postman教學大全, 這玩意也是個軟體,所以直接Windows下載安裝即可。

開啟之後, 我們新建一個collections,其實就是目錄,然後在這裡面新建一個request請求,就可以測試了。

在這裡插入圖片描述
我這裡給出我這邊的測試例子, 我當時想通過postman測試下,能不能存取到後端。測試的後端函數是這個:

@app.route('/recsys/register', methods=["POST"])
def register():
    """使用者註冊
    """
    request_str = request.get_data()
    request_dict = json.loads(request_str)
    print(request_dict)

    user = RegisterUser()
    user.username = request_dict["username"]
    user.passwd = request_dict["passwd"]

    # 查詢當前使用者名稱是否已經被用過了
    result = UserAction().user_is_exist(user, "register")

    if result != 0:
        return jsonify({"code": 500, "mgs": "this username is exists"})

    #user.userid = snowflake.client.get_guid() # 雪花演演算法
    user.userid = 20211971672
    user.age = request_dict["age"]
    user.gender = request_dict["gender"]
    user.city = request_dict["city"]
    print("hello world")

    # 新增註冊使用者
    save_res = UserAction().save_user(user)
    if not save_res:
        return jsonify({"code": 500, "mgs": "register fail."})

    return jsonify({"code": 200, "msg": "register success."})

使用者註冊函數, 這是一個post請求格式的,然後需要傳入使用者的相關引數,給到後端,後端把這個存到使用者登入檔裡面去。然後返回成功資訊。

其實邏輯很簡單,首先, 建立post請求格式在postman的操作, 首先請求格式改成POST,然後headers這裡需要設定json格式。
在這裡插入圖片描述
然後, 在body裡面傳入請求引數,也就是使用者的註冊資訊, 這裡是一個字典的形式
在這裡插入圖片描述
這樣,點選右上角send即可傳送了。根據下面後端返回的資訊,說明後端這塊是可以被存取的,沒有什麼問題。如果想傳送get請求,以及傳引數,還可以這樣:
在這裡插入圖片描述
那,這就確定了, vue框架的設定有問題。

9. 新聞推薦系統vue和flask是怎麼聯絡起來的呢?

這裡主要是記錄下解決上面這個問題的方法, 因為我這邊遇到了vue服務開啟完了之後, 輸入網址並沒有到相應的介面中去,而是報錯。 這個問題還是困擾我一段時間的,一開始以為是後端那邊的網址不能存取, 但用了postman之後,發現後端這邊沒問題。

於是我覺得是我vue那邊設定有問題,因為我對vue內部一竅不通, 並且我夥伴們之前都測試好了,不可能是程式碼方面的問題。

於是乎,開始排查路徑問題: 這篇文章啟發
在這裡插入圖片描述
這個沒有問題。下面這裡也需要改:

在這裡插入圖片描述
這樣操作完了,然後在瀏覽器輸入
在這裡插入圖片描述
這樣一頓操作之後,就搞定了上面的問題。202.199.6.190是我實驗室伺服器的地址。
在這裡插入圖片描述

當然我後端是這樣:
在這裡插入圖片描述

總結起來, 就是需要修改前端的main.js裡面的網址,然後修改package.json裡面的主機地址。 然後存取的時候是從前端running的地址進行存取。

當然,開啟前端的過程中還遇到一個奇葩的報錯問題:
在這裡插入圖片描述
這個問題我也不知道是啥原因, vue涉及到盲區, 但下面這行程式碼卻能無腦搞定,挺神奇:

# 命令列輸入
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p

到這裡就差不多了,花了兩三天的探索,終於把整個系統換了我實驗室伺服器跑出來,然後整理這篇文章記錄下, 實測能執行, 感興趣的夥伴可以玩玩啦 😉

專案地址: https://github.com/datawhalechina/fun-rec/tree/master/codes/news_recsys