[PYTHON] Überprüfen Sie einfach den Inhaltstyp mit Flask (@content_type).

1. Zuallererst

In Vorheriger Artikel habe ich eine Konzept-App für Mikrodienste mit Flask, Cerberus und Peewee erstellt. Dieses Mal werde ich erklären, wie der Inhaltstyp anhand des Kolbens überprüft wird, der zu diesem Zeitpunkt weggelassen wurde. Außerdem möchte ich vorstellen, wie ein Funktionsdekorator erstellt wird, der den Inhaltstyp überprüft.

1.1. Diesmal wurden die Spezifikationen des Funktionsdekorators @ content_type eingeführt

@content_Beispiel für die Verwendung des Type Function Decorators


# rest api
@app.route('/questions', methods=['POST'])
@content_type('application/json')
def register_question():

1.2. Verifizierungsumgebung

2. Siehe request.headers für HTTP-Anforderungsheader

In flask können Sie mit request.headers auf die HTTP-Anforderungsheaderinformationen verweisen. request.headers ist ein Objekt vom Typ Wörterbuch, dessen Schlüssel der Headername ist. Wenn Sie also den Inhaltstyp überprüfen, ermitteln Sie den Wert mit dem Inhaltstyp als Schlüssel. Weitere Informationen finden Sie unter http://flask.pocoo.org/docs/0.12/api/#incoming-request-data.

2.1. Beispielcode zur Überprüfung des Inhaltstyps (nicht gut genug)

Kein guter Beispielcode


# -*- coding: utf-8 -*-
import os
from flask import Flask, abort, request, make_response, jsonify

# flask
app = Flask(__name__)

# rest api
@app.route('/questions', methods=['POST'])
def register_question():
    #Inhaltstyp (Anwendung/json) überprüfen
    if not request.headers.get("Content-Type") == 'application/json':
        error_message = {
            'error':'not supported Content-Type'
        }
        return make_response(jsonify(error_message), 400)

    # omitted :Ausführung der Geschäftslogik
    #Rückgabe des Verarbeitungsergebnisses (JSON-Format)
    return make_response(jsonify({'result': True}))

@app.route('/questions/<string:question_code>', methods=['PUT'])
def update_question(question_code):
    #Inhaltstyp (Anwendung/json) überprüfen
    if not request.headers.get("Content-Type") == 'application/json':
        error_message = {
            'error':'not supported Content-Type'
        }
        return make_response(jsonify(error_message), 400)
    
    # omitted :Ausführung der Geschäftslogik
    #Rückgabe des Verarbeitungsergebnisses (JSON-Format)
    return make_response(jsonify({'result': True}))

# main
if __name__ == "__main__":
    app.run(host=os.getenv("APP_ADDRESS", 'localhost'), \
    port=os.getenv("APP_PORT", 3000))

2.2 Probleme mit dem Beispielcode

Da es viele Stellen gibt, an denen der Inhaltstyp überprüft werden kann, treten Probleme mit Code Clone / Duplicate Code auf. Es kann als Dienstprogrammfunktion definiert werden, aber da es die Voraussetzungen vor dem Aufrufen der API nicht erfüllt, ist es nur ein persönlicher Eindruck, aber ich wollte den Prozess des Aufrufs des Dienstprogramms nicht beschreiben.

Wenn es sich um einen Funktionsdekorateur handelt, können Sie die Zielfunktion (in diesem Fall die REST-API) nur aufrufen, wenn die Prüfung bestanden wurde, dh wenn die Voraussetzungen erfüllt sind. Aus diesem Grund habe ich mich entschlossen, den unten gezeigten Funktionsdekorator zu implementieren.

3. Erstellen Sie einen Funktionsdekorator "@ content_type" für ein modernes Erscheinungsbild

3.1. Beispielcode zur Überprüfung des Inhaltstyps

content_type_check_app.py


# -*- coding: utf-8 -*-
import os
from flask import Flask, abort, request, make_response, jsonify
import functools

# flask
app = Flask(__name__)

# check content-type decorator
def content_type(value):
    def _content_type(func):
        @functools.wraps(func)
        def wrapper(*args,**kwargs):
            if not request.headers.get("Content-Type") == value:
                error_message = {
                    'error': 'not supported Content-Type'
                }
                return make_response(jsonify(error_message), 400)

            return func(*args,**kwargs)
        return wrapper
    return _content_type

# rest api
@app.route('/questions', methods=['POST'])
@content_type('application/json')
def register_question():
    # omitted :Ausführung der Geschäftslogik
    #Rückgabe des Verarbeitungsergebnisses (JSON-Format)
    return make_response(jsonify({'result': True}))

@app.route('/questions/<string:question_code>', methods=['PUT'])
@content_type('application/json')
def update_question(question_code):
    # omitted :Ausführung der Geschäftslogik
    #Rückgabe des Verarbeitungsergebnisses (JSON-Format)
    return make_response(jsonify({'result': True}))

# main
if __name__ == "__main__":
    app.run(host=os.getenv("APP_ADDRESS", 'localhost'), \
    port=os.getenv("APP_PORT", 3000))

3.2. Ergebnis der Verwendung von @ content_type

Sie können jetzt einfach "@ content_type (" application / json ")" zu den REST-API-Funktionen hinzufügen. Sie können intuitiv erkennen, dass der Inhaltstyp application / json ohne das Problem des Klonens von Code sein sollte. (Falls erforderlich, machen Sie application / json konstant.)

** Übrigens, wenn Sie die Beschreibungsreihenfolge von "@ app.route" und "@ content_type" ändern, tritt ein Fehler auf. ** **. Python-Funktionsdekoratoren sind keine Orientierungspunkte wie Java-Annotationen, sondern Funktionsverschachtelungen. Die Reihenfolge der Verschachtelung wirkt sich also auf den Verarbeitungsablauf aus. Dies liegt daran, dass die Funktion des Kolbens bei der Verarbeitung von "@ content_type" aufgerufen wird. Daher muss der Kolben zuerst als Nest ausgeführt werden.

4. Funktionsprüfung

4.1. Client-Quellcode

democlient.py


# -*- coding: utf-8 -*-
import requests
import json

def register_question_none_content_type(url, data):
    print("[POST] /questions : none content-type")
    response = requests.post(url, json.dumps(question))
    print(response.status_code)
    print(response.content)

def register_question(url, data):
    print("[POST] /questions : content-type application/json")
    response = requests.post(url, json.dumps(question), \
        headers={'Content-type': 'application/json'})
    print(response.status_code)
    print(response.content)

# main
if __name__ == "__main__":
    url = 'http://localhost:3000/questions'
    question = {
        'question_code' : '9999999999',
        'category' : 'demo',
        'message' : 'hello'
    }
    # Content-Kein Typ
    register_question_none_content_type(url, question)
    # Content-Type : application/json
    register_question(url, question)

4.1.1 Geben Sie in Anforderungen keine Anwendung / json vom Inhaltstyp an

Wie in Vorheriger Artikel beschrieben, werden Anforderungen automatisch angewendet, wenn Sie Daten im json-Argument wie "json = data" angeben. Stellen Sie den Inhaltstyp von json ein. Da diese Funktion diesmal nicht verwendet wird, werden die direkten Übertragungsdaten (json.dumps (question)) im zweiten Argument gesetzt.

4.2 Starten Sie den Server

Serverstart (und Ausführungsprotokoll)


C:\tmp\>python content_type_check_app.py
 * Running on http://localhost:3000/ (Press CTRL+C to quit)
127.0.0.1 - - [16/Aug/2017 20:02:30] "POST /questions HTTP/1.1" 400 -
127.0.0.1 - - [16/Aug/2017 20:02:30] "POST /questions HTTP/1.1" 200 -

Die erste Zeile des Ausführungsprotokolls ist eine HTTP-Anforderung, für die kein Inhaltstyp angegeben ist, und der HTTP-Status lautet 400. Die zweite Zeile ist die angegebene HTTP-Anforderung. In diesem Fall wird der Prozess normal ausgeführt und 200 zurückgegeben.

4.3. Starten des Clients

Client-Ausführung


C:\tmp\python democlient.py
[POST] /questions : none content-type
400
{
  "error": "not supported Content-Type"
}

[POST] /questions : content-type application/json
200
{
  "result": true
}

Wir haben bestätigt, dass HTTP-Anforderungen, die keinen Inhaltstyp angeben, einen 400-Fehler mit HTTP-Status und dem Fehlerinhalt "{" Fehler ":" Nicht unterstützter Inhaltstyp "}" wie vorgesehen zurückgeben. Da die nächste Anforderung application / json für den Inhaltstyp angibt, hat sie die Prüfung des Inhaltstyps bestanden und das korrekte Verarbeitungsergebnis mit einem HTTP-Status von 200 zurückgegeben.

5. Schließlich

Dieses Mal habe ich erklärt, wie man den Inhaltstyp mit der Flasche überprüft. ** Wenn der Kolben auch mit Content-Type eine Anforderungszuordnung durchführen kann, wird Content-Type garantiert, wenn die REST-API aufgerufen wird **, sodass der diesmal erstellte @ content_type nicht erforderlich ist.

Außerdem habe ich dieses Mal zum ersten Mal einen Funktionsdekorator erstellt, aber da ich später Funktionen wie AOP hinzufügen kann, hatte ich das Gefühl, dass er auf verschiedene andere Arten verwendet werden kann.

Recommended Posts

Überprüfen Sie einfach den Inhaltstyp mit Flask (@content_type).
Bild-Uploader mit Flasche
HTTP-Umgebungsvariablen in Flask
Sellerie asynchrone Verarbeitung in Flask
Hochladen mehrerer Dateien mit Flask
Suchen Sie mit Python nach externen Befehlen
Erstellen Sie mit Flask einen CSV-Reader
Problem, bei dem Apscheduler zweimal in Flask ausgeführt wurde - gefixt
Informationen zur Parameterverarbeitung in Flask's request.args
Überprüfen und verschieben Sie das Verzeichnis in Python
Überprüfen Sie die Datenzusammenfassung in CASTable
Best Practices für Konfigurationsdateien in Flask