【Python使用】嘿馬頭條項(xiàng)目從到完整開(kāi)發(fā)教程第6篇:Git工用流,調(diào)試方法【附代碼文檔】

??????教程全知識(shí)點(diǎn)簡(jiǎn)介:1.APScheduler任務(wù)調(diào)度涵蓋安裝配置、使用方式、調(diào)度器Scheduler、執(zhí)行器executors、觸發(fā)器Trigger等核心組件。2. RPC遠(yuǎn)程過(guò)程調(diào)用包括RPC概念、背景用途、優(yōu)缺點(diǎn)分析。3. Protocol Buffers數(shù)據(jù)序列化涉及文檔結(jié)構(gòu)、注釋語(yǔ)法、數(shù)據(jù)類型、枚舉類型、消息類型(字段編號(hào)、字段規(guī)則、嵌套類型、保留字段、默認(rèn)值)。4. 客戶端開(kāi)發(fā)包含頭條首頁(yè)新聞推薦接口編寫(xiě)。5. 即時(shí)通訊技術(shù)涵蓋需求場(chǎng)景、傳統(tǒng)推送實(shí)現(xiàn)、Socket.IO(Python服務(wù)器端開(kāi)發(fā)、事件處理)。6. Elasticsearch搜索引擎包括簡(jiǎn)介原理、倒排索引、分析器、相關(guān)性排序、集群概念、IK中文分析器、索引類型、文檔操作(索引文檔、獲取文檔、判斷存在、更新刪除)、Logstash數(shù)據(jù)導(dǎo)入、查詢(基本查詢、高級(jí)查詢)、全文檢索實(shí)現(xiàn)、Python客戶端使用、聯(lián)想提示(拼寫(xiě)糾錯(cuò)、自動(dòng)補(bǔ)全)。7. 單元測(cè)試涵蓋測(cè)試分類、基本寫(xiě)法、測(cè)試必要性。8. 服務(wù)器部署包括Gunicorn、Supervisor配置管理。9. 項(xiàng)目開(kāi)發(fā)流程涉及產(chǎn)品介紹、原型圖UI圖、技術(shù)架構(gòu)、開(kāi)發(fā)環(huán)境(ToutiaoWeb虛擬機(jī)、Pycharm遠(yuǎn)程開(kāi)發(fā))。10. 數(shù)據(jù)庫(kù)技術(shù)包含ORM理解、SQLAlchemy映射構(gòu)建、數(shù)據(jù)庫(kù)連接設(shè)置、模型類字段選項(xiàng)。11. 分布式系統(tǒng)涵蓋分布式ID方案選擇、Twitter Snowflake算法(64位ID劃分、最大取值計(jì)算、移位偏移計(jì)算、序號(hào)循環(huán)掩碼、時(shí)間戳處理)。12. Redis數(shù)據(jù)庫(kù)包括Redis持久化機(jī)制。13. Git工作流涵蓋Gitflow工作流(工作方式、歷史分支、功能分支、發(fā)布分支、維護(hù)分支)、調(diào)試方法。14. 身份認(rèn)證技術(shù)包含JWT、JWS、JWE概念、Python庫(kù)使用、項(xiàng)目封裝實(shí)施方案。15. 對(duì)象存儲(chǔ)涉及OSS對(duì)象存儲(chǔ)、七牛云存儲(chǔ)服務(wù)。16. 緩存系統(tǒng)包括緩存架構(gòu)、緩存數(shù)據(jù)保存方式、緩存有效期TTL、緩存淘汰策略、緩存問(wèn)題(緩存穿透、緩存雪崩)、頭條項(xiàng)目緩存設(shè)計(jì)(User Cache、Article Cache、Announcement Cache)、持久存儲(chǔ)設(shè)計(jì)(閱讀歷史、搜索歷史、統(tǒng)計(jì)數(shù)據(jù))。


??????????本站這篇博客:???http://www.itdecent.cn/p/043de7e784eb 中查看

??????????本站這篇博客:???http://www.itdecent.cn/p/043de7e784eb 中查看

? 本教程項(xiàng)目亮點(diǎn)

?? 知識(shí)體系完整:覆蓋從基礎(chǔ)原理、核心方法到高階應(yīng)用的全流程內(nèi)容
?? 全技術(shù)鏈覆蓋:完整前后端技術(shù)棧,涵蓋開(kāi)發(fā)必備技能
?? 從零到實(shí)戰(zhàn):適合 0 基礎(chǔ)入門到提升,循序漸進(jìn)掌握核心能力
?? 豐富文檔與代碼示例:涵蓋多種場(chǎng)景,可運(yùn)行、可復(fù)用
?? 工作與學(xué)習(xí)雙參考:不僅適合系統(tǒng)化學(xué)習(xí),更可作為日常開(kāi)發(fā)中的查閱手冊(cè)
?? 模塊化知識(shí)結(jié)構(gòu):按知識(shí)點(diǎn)分章節(jié),便于快速定位和復(fù)習(xí)
?? 長(zhǎng)期可用的技術(shù)積累:不止一次學(xué)習(xí),而是能伴隨工作與項(xiàng)目長(zhǎng)期參考


??????全教程總章節(jié)


??????本篇主要內(nèi)容

Git工用流

調(diào)試方法

  1. 判斷問(wèn)題發(fā)生在前端還是后端
  • 如果前端為網(wǎng)頁(yè),可以通過(guò)網(wǎng)頁(yè)調(diào)試工具里面的network判斷

    • 在前端中觸發(fā)一次接口調(diào)用的請(qǐng)求
    • 查看network中對(duì)應(yīng)的請(qǐng)求記錄
    • 如果沒(méi)有發(fā)現(xiàn)有新的請(qǐng)求記錄,表示前端有問(wèn)題,并未發(fā)起請(qǐng)求
    • 如果有請(qǐng)求記錄,返回的狀態(tài)碼為200,但是頁(yè)面沒(méi)有想要的效果,表示前端沒(méi)有正確處理200的響應(yīng)
    • 如果返回的狀態(tài)碼為4xx, 表示前端構(gòu)造的請(qǐng)求有問(wèn)題,比如404沒(méi)有正確的請(qǐng)求網(wǎng)址,401、403請(qǐng)求的身份有問(wèn)題,405請(qǐng)求的方式有問(wèn)題,400表示構(gòu)造的請(qǐng)求參數(shù)不正確(類型不對(duì)或缺少參數(shù))
    • 如果返回500狀態(tài)碼,表示服務(wù)器端出現(xiàn)問(wèn)題
  • 如果前端不是網(wǎng)頁(yè),比如app,通過(guò)日志的訪問(wèn)請(qǐng)求記錄判斷

在服務(wù)器中查看日志文件的方法:

tail flask.log  # 查看最后一條記錄
  tail -n 100 flask.log  # 查看最新的100條記錄
  tail -f flask.log  # 實(shí)時(shí)查看
  1. 如果是后端出現(xiàn)的問(wèn)題,通過(guò)pycharm或日志來(lái)判斷
  • 查看記錄錯(cuò)誤的日志,根據(jù)日志的信息判斷錯(cuò)誤

Git工用流

JWT & JWS & JWE

Json Web Token(JWT)

JSON Web Token(JWT)是一個(gè)非常輕巧的規(guī)范。這個(gè)規(guī)范允許我們使用JWT在兩個(gè)組織之間傳遞安全可靠的信息。

官方定義:JSON Web Token (JWT) is a compact URL-safe means of representing claims to be transferred between two parties

現(xiàn)在網(wǎng)上大多數(shù)介紹JWT的文章實(shí)際介紹的都是JWS(JSON Web Signature),也往往導(dǎo)致了人們對(duì)于JWT的誤解,但是JWT并不等于JWS,JWS只是JWT的一種實(shí)現(xiàn),除了JWS外,JWE(JSON Web Encryption)也是JWT的一種實(shí)現(xiàn)。

下面就來(lái)詳細(xì)介紹一下JWT與JWE的兩種實(shí)現(xiàn)方式:

python-multipart 文檔

JSON Web Signature(JWS)

JSON Web Signature是一個(gè)有著簡(jiǎn)單的統(tǒng)一表達(dá)形式的字符串:

頭部(Header)

頭部用于描述關(guān)于該JWT的最基本的信息,例如其類型以及簽名所用的算法等。 JSON內(nèi)容要經(jīng)Base64 編碼生成字符串成為Header。

載荷(PayLoad)

payload的五個(gè)字段都是由JWT的標(biāo)準(zhǔn)所定義的。

  1. iss: 該JWT的簽發(fā)者
  2. sub: 該JWT所面向的用戶
  3. aud: 接收該JWT的一方
  4. exp(expires): 什么時(shí)候過(guò)期,這里是一個(gè)Unix時(shí)間戳
  5. iat(issued at): 在什么時(shí)候簽發(fā)的

后面的信息可以按需補(bǔ)充。 JSON內(nèi)容要經(jīng)Base64 編碼生成字符串成為PayLoad。

簽名(signature)

這個(gè)部分header與payload通過(guò)header中聲明的加密方式,使用密鑰secret進(jìn)行加密,生成簽名。 JWS的主要目的是保證了數(shù)據(jù)在傳輸過(guò)程中不被修改,驗(yàn)證數(shù)據(jù)的完整性。但由于僅采用Base64對(duì)消息內(nèi)容編碼,因此不保證數(shù)據(jù)的不可泄露性。所以不適合用于傳輸敏感數(shù)據(jù)。

JSON Web Encryption(JWE)

相對(duì)于JWS,JWE則同時(shí)保證了安全性與數(shù)據(jù)完整性。 JWE由五部分組成:

JWE組成

具體生成步驟為:

  1. JOSE含義與JWS頭部相同。
  2. 生成一個(gè)隨機(jī)的Content Encryption Key (CEK)。
  3. 使用RSAES-OAEP 加密算法,用公鑰加密CEK,生成JWE Encrypted Key。
  4. 生成JWE初始化向量。
  5. 使用AES GCM加密算法對(duì)明文部分進(jìn)行加密生成密文Ciphertext,算法會(huì)隨之生成一個(gè)128位的認(rèn)證標(biāo)記Authentication Tag。 6.對(duì)五個(gè)部分分別進(jìn)行base64編碼。

可見(jiàn),JWE的計(jì)算過(guò)程相對(duì)繁瑣,不夠輕量級(jí),因此適合與數(shù)據(jù)傳輸而非token認(rèn)證,但該協(xié)議也足夠安全可靠,用簡(jiǎn)短字符串描述了傳輸內(nèi)容,兼顧數(shù)據(jù)的安全性與完整性。

JWT的Python庫(kù)

獨(dú)立的JWT Python庫(kù)

  • itsdangerous

    • JSONWebSignatureSerializer
    • TimedJSONWebSignatureSerializer (可設(shè)置有效期)
  • pyjwt

https://pyjwt.readthedocs.io/en/latest/

安裝

$ pip install pyjwt

用例

>>> import jwt

  >>> encoded_jwt = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256')
  >>> encoded_jwt
  'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg'

  >>> jwt.decode(encoded_jwt, 'secret', algorithms=['HS256'])
  {'some': 'payload'}

頭條項(xiàng)目封裝

import jwt
from flask import current_app


def generate_jwt(payload, expiry, secret=None):
    """
    生成jwt
    :param payload: dict 載荷
    :param expiry: datetime 有效期
    :param secret: 密鑰
    :return: jwt
    """
    _payload = {'exp': expiry}
    _payload.update(payload)

    if not secret:
        secret = current_app.config['JWT_SECRET']

    token = jwt.encode(_payload, secret, algorithm='HS256')
    return token.decode()


def verify_jwt(token, secret=None):
    """
    檢驗(yàn)jwt
    :param token: jwt
    :param secret: 密鑰
    :return: dict: payload
    """
    if not secret:
        secret = current_app.config['JWT_SECRET']

    try:
        payload = jwt.decode(token, secret, algorithm=['HS256'])
    except jwt.PyJWTError:
        payload = None

    return payload

paramiko 文檔

頭條項(xiàng)目實(shí)施方案

需求

設(shè)置有效期,但有效期不宜過(guò)長(zhǎng),需要刷新。

如何解決刷新問(wèn)題?

  • 手機(jī)號(hào)+(或帳號(hào)+ )驗(yàn)證后頒發(fā)接口調(diào)用token與refresh_token(刷新token)

  • Token 有效期為2小時(shí),在調(diào)用接口時(shí)攜帶,每2小時(shí)刷新一次

  • 提供refresh_token,refresh_token 有效期14天

  • 在接口調(diào)用token過(guò)期后憑借refresh_token 獲取新token

  • 未攜帶token 、錯(cuò)誤的token或接口調(diào)用token過(guò)期,返回401狀態(tài)碼

  • refresh_token 過(guò)期返回403狀態(tài)碼,前端在使用refresh_token請(qǐng)求新token時(shí)遇到403狀態(tài)碼則進(jìn)入用戶登錄界面從新認(rèn)證。

  • token的攜帶方式是在請(qǐng)求頭中使用如下格式:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg

注意:Bearer前綴與token中間有一個(gè)空格

實(shí)現(xiàn)

注冊(cè)或登錄獲取token

toutiao/resources/user/passport.pty

class AuthorizationResource(Resource):
    """
    認(rèn)證
    """
    def _generate_tokens(self, user_id, with_refresh_token=True):
        """
        生成token 和refresh_token
        :param user_id: 用戶id
        :return: token, refresh_token
        """
         # 頒發(fā)JWT
        now = datetime.utcnow()
        expiry = now + timedelta(hours=current_app.config['JWT_EXPIRY_HOURS'])
        token = generate_jwt({'user_id': user_id, 'refresh': False}, expiry)
        refresh_token = None
        if with_refresh_token:
            refresh_expiry = now + timedelta(days=current_app.config['JWT_REFRESH_DAYS'])
            refresh_token = generate_jwt({'user_id': user_id, 'refresh': True}, refresh_expiry)
        return token, refresh_token

    def post(self):
        """
        登錄創(chuàng)建token
        """
        json_parser = RequestParser()
        json_parser.add_argument('mobile', type=parser.mobile, required=True, location='json')
        json_parser.add_argument('code', type=parser.regex(r'^\d{6}$'), required=True, location='json')
        args = json_parser.parse_args()
        mobile = args.mobile
        code = args.code

        # 從redis中獲取
        key = 'app:code:{}'.format(mobile)
        try:
            real_code = current_app.redis_master.get(key)
        except ConnectionError as e:
            current_app.logger.error(e)
            real_code = current_app.redis_slave.get(key)

        try:
            current_app.redis_master.delete(key)
        except ConnectionError as e:
            current_app.logger.error(e)

        if not real_code or real_code.decode() != code:
            return {'mes
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容