简体   繁体   中英

Serve static files with flask on development and nginx on production

Let's say I've got this mcve:

mcve.py

import textwrap
from pathlib import Path
from flask import Flask


working_dir = Path(__file__).parent
app = Flask(
    __name__,
    # static_folder=str(working_dir / "uploads"),
)


@app.route("/test")
def index():
    return textwrap.dedent(
        """
        <!DOCTYPE html>
        <html>
        <head>
            <title>Hello world</title>
        </head>
        <body>
            <img src="foo/foo.png">
            <img src="bar/bar.png">
        </body>
        </html>
    """
    ).strip()


if __name__ == "__main__":
    with app.test_client() as c:
        print(c.get("/test").data.decode("utf-8"))

run.bat

set FLASK_APP=mcve.py
set FLASK_ENV=development
flask run

If I execute run.bat and then I go to http://localhost:5000/test in the browser I'll get:

>flask run
 * Serving Flask app "x.py" (lazy loading)
 * Environment: development
 * Debug mode: on
 * Restarting with windowsapi reloader
 * Debugger is active!
 * Debugger PIN: 497-008-397
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [31/May/2020 22:32:19] "GET / HTTP/1.1" 404 -
127.0.0.1 - - [31/May/2020 22:32:22] "GET /test HTTP/1.1" 200 -
127.0.0.1 - - [31/May/2020 22:32:22] "GET /foo/foo.png HTTP/1.1" 404 -
127.0.0.1 - - [31/May/2020 22:32:22] "GET /bar/bar.png HTTP/1.1" 404 -

Question

How should I modify mcve.py to server the images properly (now you can see is giving 404) in development using flask's server but then serve them properly with nginx on production?

You don't have to configure flask specifically for this. These logs:

127.0.0.1 - - [31/May/2020 22:32:19] "GET / HTTP/1.1" 404 -
127.0.0.1 - - [31/May/2020 22:32:22] "GET /test HTTP/1.1" 200 -
127.0.0.1 - - [31/May/2020 22:32:22] "GET /foo/foo.png HTTP/1.1" 404 -
127.0.0.1 - - [31/May/2020 22:32:22] "GET /bar/bar.png HTTP/1.1" 404 -

are actually generated by the werkzeug development server that's serving the static content for you. When you move to using nginx, you can intercept the GET requests with a URL rule. From the example nginx config file from the Flask Mega Tutorial :

...

server {

    ...

    location / {
        # forward application requests to the gunicorn server
        proxy_pass http://localhost:8000;
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location /static {
        # handle static files directly, without forwarding to the application
        alias /home/ubuntu/microblog/app/static;
        expires 30d;
    }
}

Note the /location rule that handles requests to static directly, so those requests from the browser wouldn't even hit whatever is serving your flask app in production. There are many more methods for matching urls that you can find, eg here . It's perfectly possible to add multiple such rules to look in separate locations but you'll want to structure the app to give these files a distinct location so you can implement such rules.


Separately, to get around your current 404s, look at thetemplate docs for Jinja2 and use the url_for method to make sure it resolves relative paths correctly.

For example, if I want to include:

<link href='static/css/bootstrap-4.3.1.min.css' rel="stylesheet">

I would instead use:

<link href="{{ url_for('static', filename='css/bootstrap-4.3.1.min.css') }}" rel="stylesheet">

This passes off the responsibility of path resolution to the app, so no matter how many hyperlinks I've followed or blueprints I'm using, this path will always resolve to the correct static directory when the template is rendered.

I'm not sure this will work with return textwrap.dedent because it might not invoke Jinja on the template. You can import render_template_string for a throwaway example like you have here, but render_template will work in your actual app too.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM