[PYTHON] Zeigen Sie eine Webseite mit FastAPI + uvicorn + Nginx an (Vorlagenfunktion von Jinja2)

0. Einleitung

Übung: Webseitenfunktion hinzugefügt

1. Paket hinzufügen

--Jinja2 für die Vorlagenfunktion erfordert die zusätzliche Installation von aiofiles, um statische Dateien zu liefern

pyproject.toml(Ergänzungen)


[tool.poetry.dependencies]
#Die folgenden zwei wurden hinzugefügt
jinja2 = "*"
aiofiles = "*"

Insgesamt zum Beispiel:

pyproject.toml


[tool.poetry]
name = "test_fastapi_app"
version = "0.1.0"
description = "just for test"
authors = ["Your Name <[email protected]>"]

[tool.poetry.dependencies]
python = "^3.8"
uvicorn = "*"
fastapi = "*"
jinja2 = "*"
aiofiles = "*"

[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"

2. Ändern / fügen Sie den Inhalt von app hinzu

Dateistruktur (app)

$ tree
.
├── app
│   ├── Dockerfile
│   ├── app
│   │   ├── __init__.py
│   │   ├── main.py
│   │   ├── routers
│   │   │   ├── __init__.py
│   │   │   └── subpage.py
│   │   ├── static
│   │   │   ├── layout.css
│   │   │   └── subpage
│   │   │       ├── test.css
│   │   │       └── test.js
│   │   └── templates
│   │       ├── layout.html
│   │       └── subpage
│   │           └── index.html
│   ├── poetry.lock
│   └── pyproject.toml
├── docker-compose.yml
└── web

Da die Dateien in app / app geändert / hinzugefügt wurden, werden wir uns die Details unten ansehen.

main.py

main.py


"""                         
app main                      
"""                        
                      
import pathlib
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.responses import RedirectResponse

from .routers import subpage

# pathlib.Ermitteln Sie den absoluten Pfad eines statischen Verzeichnisses mithilfe von Pfad
PATH_STATIC = str(pathlib.Path(__file__).resolve().parent / "static")


def create_app():
    """
    create app

    -Es wird ein wenig kompliziert, also ist es funktionalisiert
    """
    _app = FastAPI()

    #Unter-App des Routermoduls`subpage`URL"/subpage/"Unten montieren
    _app.include_router(
        subpage.router,
        prefix="/subpage",
        tags=["subpage"],
        responses={404: {"description": "not found"}},
    )

    # static
    # URL`/static"Hängen Sie die statische Datei unten ein
    _app.mount(
        "/static",
        StaticFiles(directory=PATH_STATIC, html=False),
        name="static",
    )

    return _app


app = create_app()


@app.get('/')
async def redirect_subpage():
    """redirect webpage"""
    return RedirectResponse( #Weiterleiten zu einer Webseite, die mit einer Unterseiten-Unter-App erstellt wurde
        "/subpage",
    )

Die Anzahl der Zeilen hat sich etwas erhöht, aber ich mache hauptsächlich

--Zusatz von "statisch" --Sub-App: Subpage einbinden und umleiten

routers/subpage.py

routers/subpage.py


"""
test subpage
"""

import pathlib

from fastapi import (
    APIRouter,
    Request,
)
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse

#Rufen Sie den absoluten Pfad des Vorlagenverzeichnisses ab
PATH_TEMPLATES = str(
    pathlib.Path(__file__).resolve() \
        .parent.parent / "templates"
)
#Jinja2-Objekterzeugung
templates = Jinja2Templates(directory=PATH_TEMPLATES)


#Unter-App
router = APIRouter()


@router.get("/", response_class=HTMLResponse)
async def site_root(
    request: Request,
):
    """test subpage"""
    title = "test subpage"
    return templates.TemplateResponse(
        "subpage/index.html",   # `templates`Relativer Pfad im Verzeichnis
        context={   #Variablen können im Diktatformat übergeben werden
            "request": request,
            "title": title,
        }
    )

templates Verzeichnis

layout.html

layout.html


<!DOCTYPE html>
<html lang="ja">
    <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, shrink-to-fit=no">
        <meta name="apple-mobile-web-app-capable" content="yes">
        {% if title %}
            <title>{{ title }}</title>
        {% else %}
            <title>Template</title>
        {% endif %}

        <!-- jQuery & Bootstrap4 -->
        <script
            src="https://code.jquery.com/jquery-3.4.1.min.js"
            integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
            crossorigin="anonymous"></script>
        <link
            rel="stylesheet"
            href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
            integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
            crossorigin="anonymous">

        <script
            src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js"
            integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
            crossorigin="anonymous"></script>
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
            integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
            crossorigin="anonymous"></script>

        <!-- jQuery UI -->
        <script
            src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"
            integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU="
            crossorigin="anonymous"></script>
        <link
            rel="stylesheet"
            type="text/css"
            href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.min.css">

        <!-- CUSTOM STYLE -->
        <link rel="stylesheet" type="text/css" href="{{url_for('static', path='/layout.css')}}">
        {% block head %}{% endblock %}

    </head>

    <body>
        {% block content %}{% endblock %}
    </body>

</html>

subpage/index.html

subpage/index.html


{% extends "layout.html" %}

{% block head %}
<link
    rel="stylesheet"
    type="text/css"
    href="{{ url_for('static', path='/subpage/test.css')  }}">
<script
    type="text/javascript"
    src="{{ url_for('static', path='subpage/test.js') }}"></script>
{% endblock %}


{% block content %}
<h2>Test Subpage</h2>

<br>

<h3>
    Hello, World.
</h3>

{% endblock %}

statisches Verzeichnis

--Details werden weggelassen, da sie nur zum Testen dienen und praktisch kein Inhalt vorhanden ist. ――Wir werden später bestätigen, dass der Inhalt zur Laufzeit ordnungsgemäß gelesen werden kann.

3. Ausführung (1)

Mach Folgendes

#Paket hinzugefügt, Quelle geändert / hinzugefügt, also neu erstellen
docker-compose build

#Dienststart
docker-compose up -d

Wenn Sie in einer lokalen Umgebung ausgeführt werden, sehen Sie sich http: // localhost an

スクリーンショット 2020-08-16 00-28-56.png

スクリーンショット 2020-08-16 00-34-01.png

Auf den ersten Blick scheint es zu funktionieren, aber wenn Sie genau hinschauen, können Sie die statische Datei nicht aus HTML lesen:

<link rel="stylesheet" type="text/css" href="http://backend/static/layout.css">
        
<link
    rel="stylesheet"
    type="text/css"
    href="http://backend/static/subpage/test.css">
<script
    type="text/javascript"
    src="http://backend/static/subpage/test.js"></script>

Da es in diesem Bereich ein Proxy-Problem gibt, müssen die Startoption von "uvicorn" und die Einstellung von "nginx" geändert werden, um dieses Problem zu beheben.

4. Einstellungen ändern und ausführen (Teil 2)

4-1. uvicorn

Ändern Sie abschließend die "CMD" der Docker-Datei wie folgt, um die Startoption von "uvicorn" zu korrigieren

Dockerfile (Korrektur)


# CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0"]
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--proxy-headers", "--forwarded-allow-ips", "*"]

4-2. Nginx

Ändern Sie als Nächstes die Nginx-Konfigurationsdatei (web / conf.d / app.conf). (Ein Beispiel für Nginx finden Sie unter uvicorns Bereitstellung.)

$ tree    
.
├── app
├── docker-compose.yml
└── web
    └── conf.d
        └── app.conf

-Modifizieren Sie app.conf in ↑ wie folgt

conf:conf.d/app.conf


upstream backend {
    server app:8000;
}

server {
    listen 80;
    # server_name  localhost;
    # index index.html index.htm;

    location / {
        #Die folgenden 5 Elemente wurden hinzugefügt
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_redirect off;
        proxy_buffering off;

        proxy_pass http://backend;
    }

    # log
    # access_log /var/log/nginx/access.log;
    # error_log /var/log/nginx/error.log;
}

# server_tokens off;

Wenn Sie dies bisher tun, wird die erwartete URL korrekt wie "http: // localhost / " aufgerufen, selbst wenn Sie "url_for" für die HTML-Datei ausführen.

image.png

Zusammenfassung

--FastAPI + uvicorn + Nginx (Docker-Compose) -Konfiguration zum Erstellen einer Webfunktion mit der Atmosphäre von Flask --Flask ist einfacher zu verwenden, wenn Webfunktionen mit der Vorlagenfunktion usw. erstellt werden, und ich fand es einfacher, weil es viele Dokumente gibt. --FastAPI ist auf RestAPI-Funktionen spezialisiert und eignet sich möglicherweise nicht für Webfunktionen. Wenn Sie jedoch die asynchrone Verarbeitung beherrschen, besteht möglicherweise Leistungspotenzial.

Referenz

Recommended Posts

Zeigen Sie eine Webseite mit FastAPI + uvicorn + Nginx an (Vorlagenfunktion von Jinja2)
Webseite mit FastAPI + uvicorn + Nginx anzeigen (SSL / HTTPS-Konvertierung)
Erstellen Sie FastAPI + uvicorn + nginx mit Docker-Compose
Extrahieren Sie mit Python Daten von einer Webseite
Starten Sie mit Docker eine Python-Webanwendung auf Nginx + Gunicorn
Holen Sie sich Python-Webseite, Zeichenkodierung und Anzeige
Google Maps auf der Webseite anzeigen (Spring Boot + Thymeleaf)
[Python, Ruby] Selen-Holen Sie sich Webseiteninhalte mit Webdriver
Entwicklungspraxis für Webanwendungen: Erstellen Sie mit Django eine Seite zum Erstellen von Schichten! (Schichterstellungsseite)
[FastAPI] Erste Schritte mit FastAPI, einem ASGI-Webframework von Python