Pliki statyczne we Flask - robot.txt, sitemap.xml (mod_wsgi)

94

Czy istnieje sprytne rozwiązanie do przechowywania plików statycznych w katalogu głównym aplikacji Flask? Pliki robots.txt i sitemap.xml powinny znajdować się w /, więc moim pomysłem było utworzenie dla nich tras:

@app.route('/sitemap.xml', methods=['GET'])
def sitemap():
  response = make_response(open('sitemap.xml').read())
  response.headers["Content-type"] = "text/plain"
  return response

Musi być coś wygodniejszego :)

biesiad
źródło

Odpowiedzi:

78

Najlepszym sposobem jest ustawienie static_url_path na główny adres URL

from flask import Flask

app = Flask(__name__, static_folder='static', static_url_path='')
dns
źródło
Warto wspomnieć, że static_folder nie musi znajdować się w folderze projektu. np. static_folder = „/ app / ui” jest w porządku.
ashic
66

@vonPetrushev ma rację, w produkcji będziesz chciał obsługiwać pliki statyczne przez nginx lub apache, ale w przypadku programowania dobrze jest mieć proste środowisko programistyczne, w którym aplikacja Python obsługuje również statyczną zawartość, więc nie musisz się martwić o zmianie konfiguracji i wielu projektach. Aby to zrobić, będziesz chciał użyć SharedDataMiddleware .

from flask import Flask
app = Flask(__name__)
'''
Your app setup and code
'''
if app.config['DEBUG']:
    from werkzeug import SharedDataMiddleware
    import os
    app.wsgi_app = SharedDataMiddleware(app.wsgi_app, {
      '/': os.path.join(os.path.dirname(__file__), 'static')
    })

Ten przykład zakłada, że ​​Twoje pliki statyczne znajdują się w folderze „static”, dostosuj je do tego, co pasuje do Twojego środowiska.

Philip Southam
źródło
1
DZIĘKI! To jest to, czego potrzebowałem! Chcę to zrobić dla mojego heroku produkcyjnego. Zobacz odpowiedzi w następującym wątku: flask.pocoo.org/mailinglist/archive/2012/2/22/…
David
2
Uwaga - teraz jest łatwiejszy sposób, aby sobie z tym poradzić. Sprawdź moją odpowiedź.
Sean McSomething,
1
Czy istnieje sposób, aby SharedDataMiddleware rozpoznał tylko „/” do pliku index.html lub podobnego?
gromgull,
63

Najczystszą odpowiedzią na to pytanie jest odpowiedź na to (identyczne) pytanie :

from flask import Flask, request, send_from_directory
app = Flask(__name__, static_folder='static')    

@app.route('/robots.txt')
@app.route('/sitemap.xml')
def static_from_root():
    return send_from_directory(app.static_folder, request.path[1:])

Podsumowując:

  • jak zauważył David, z odpowiednią konfiguracją można obsłużyć kilka statycznych plików przez prod
  • szukanie /robots.txt nie powinno skutkować przekierowaniem do /static/robots.txt. (W odpowiedzi Seans nie jest od razu jasne, jak to się osiągnęło.)
  • dodawanie plików statycznych do folderu głównego aplikacji nie jest czyste
  • wreszcie, proponowane rozwiązanie wygląda na znacznie czystsze niż podejście polegające na dodawaniu oprogramowania pośredniego:
bebbi
źródło
23

Mimo że jest to stare pytanie, odpowiadam na nie, ponieważ ten post pojawia się dość wysoko w wynikach Google. Chociaż nie jest to uwzględnione w dokumentacji, jeśli czytasz dokumentację API dla konstruktora obiektów Flask Application, jest to objęte. Przekazując nazwany parametr w ten static_foldersposób:

from flask import Flask
app = Flask(__name__,
            static_folder="/path/to/static",
            template_folder="/path/to/templates")

... możesz określić, skąd mają być obsługiwane pliki statyczne. Podobnie, możesz zdefiniować swoje template_folderimię static_url_path.

Sean McSomething
źródło
@chmike tak, domyślnie, /staticale możesz to zmienić, zastępując static_url_path.
Sean McSomething
To prawda, ale inne odpowiedzi są bardziej elastyczne. Ten jest ograniczony przez fakt, że może obsługiwać tylko jedną ścieżkę katalogu.
Thomas Dignan,
To nie jest odpowiedź na pierwotne pytanie.
Paolo Casciello
2
Jeśli ustawisz static_url_path na „”, możesz udostępniać pliki z /.
Beau,
Zmusza to Flask do obsługi plików statycznych. A co jeśli chcesz, aby serwował im Nginx lub Apache?
Markon,
15

Obsługa plików statycznych nie ma nic wspólnego z aplikacją, która ma dostarczać dynamiczną zawartość. Prawidłowy sposób obsługi plików statycznych zależy od używanego serwera. W końcu po uruchomieniu i uruchomieniu aplikacji będziesz musiał powiązać ją z serwerem internetowym. Mogę mówić tylko o apache httpd, więc sposób obsługi plików statycznych jest zdefiniowany na hoście wirtualnym, który łączysz z aplikacją za pomocą mod-wsgi. Oto przewodnik, który pokaże Ci, jak udostępniać mapy witryn, plik robots.txt lub dowolną zawartość statyczną: http://code.google.com/p/modwsgi/wiki/QuickConfigurationGuide#Mounting_At_Root_Of_Site

vonPetrushev
źródło
To odpowiedź, której szukałem. Dzięki!
biesiad
1
Aplikacja ma dostarczać treść, część dynamiczną, a część statyczną.
Dem Pilafian
14

Innym sposobem wysyłania plików statycznych jest użycie reguły catch-all, takiej jak ta:

@app.route('/<path:path>')
def catch_all(path):
    if not app.debug:
        flask.abort(404)
    try:
        f = open(path)
    except IOError, e:
        flask.abort(404)
        return
    return f.read()

Używam tego, aby zminimalizować konfigurację podczas programowania. Pomysł pochodzi z http://flask.pocoo.org/snippets/57/

Co więcej, pracuję przy użyciu Flask na mojej samodzielnej maszynie, ale wdrażam z Apache na serwerze produkcyjnym. Używam:

file_suffix_to_mimetype = {
    '.css': 'text/css',
    '.jpg': 'image/jpeg',
    '.html': 'text/html',
    '.ico': 'image/x-icon',
    '.png': 'image/png',
    '.js': 'application/javascript'
}
def static_file(path):
    try:
        f = open(path)
    except IOError, e:
        flask.abort(404)
        return
    root, ext = os.path.splitext(path)
    if ext in file_suffix_to_mimetype:
        return flask.Response(f.read(), mimetype=file_suffix_to_mimetype[ext])
    return f.read()

[...]

if __name__ == '__main__':
    parser = optparse.OptionParser()
    parser.add_option('-d', '--debug', dest='debug', default=False,
                      help='turn on Flask debugging', action='store_true')

    options, args = parser.parse_args()

    if options.debug:
        app.debug = True
        # set up flask to serve static content
        app.add_url_rule('/<path:path>', 'static_file', static_file)
    app.run()
Ben Golding
źródło
1
Uwaga - teraz jest łatwiejszy sposób, aby sobie z tym poradzić. Sprawdź moją odpowiedź.
Sean McSomething
Doskonały sposób, jeśli musisz obsługiwać wiele ścieżek!
Thomas Dignan,
6

Mogło to zostać dodane od czasu zadania tego pytania, ale przeglądałem plik „helpers.py” flask i znalazłem flask.send_from_directory:

send_from_directory(directory, filename, **options)
'''
  send_from_directory(directory, filename, **options)
  Send a file from a given directory with send_file.  This
  is a secure way to quickly expose static files from an upload folder
  or something similar.
'''

... który odwołuje się do flask.send_file:

send_file(filename_or_fp, mimetype=None, as_attachment=False, attachment_filename=None, add_etags=True, cache_timeout=43200, conditional=False)

... co wydaje się lepsze dla większej kontroli, chociaż send_from_directory przekazuje ** opcje bezpośrednio do send_file.

blast_hardcheese
źródło
3

Z dokumentacji tutaj: http://flask.pocoo.org/docs/quickstart/#static-files

Dynamiczne aplikacje internetowe również wymagają plików statycznych. Zwykle stamtąd pochodzą pliki CSS i JavaScript. W idealnym przypadku serwer WWW jest skonfigurowany tak, aby służył za Ciebie, ale Flask może to zrobić również podczas programowania. Po prostu utwórz folder o nazwie static w swoim pakiecie lub obok modułu, a będzie on dostępny w / static w aplikacji.

Aby wygenerować adresy URL do tej części adresu URL, użyj specjalnej „statycznej” nazwy adresu URL:

url_for ('statyczny', nazwa_pliku = 'style.css')

Plik musi być przechowywany w systemie plików jako static / style.css.

Josh Klein
źródło
0

Ja też mam ten sam dylemat. Poszukałem i znalazłem odpowiedź (MHO):

Równie dobrze można cytować z dokumentacji

Dynamiczne aplikacje internetowe również wymagają plików statycznych. Zwykle stamtąd pochodzą pliki CSS i JavaScript. W idealnym przypadku serwer WWW jest skonfigurowany tak, aby służył za Ciebie, ale Flask może to zrobić również podczas programowania . Po prostu utwórz folder o nazwie static w swoim pakiecie lub obok modułu, a będzie on dostępny w / static w aplikacji.

IMHO: Gdy aplikacja jest gotowa do produkcji , statyczne serwowanie plików powinno być (lub jest idealnie) skonfigurowane na serwerze internetowym (nginx, apache); ale podczas rozwoju Flask udostępnił go do obsługi plików statycznych. Ma to pomóc w szybkim rozwoju - nie ma potrzeby konfigurowania serwerów WWW i tym podobnych.

Mam nadzieję, że to pomoże.

jpanganiban
źródło
0

Spróbuj tego:

@app.route("/ProtectedFolder/<path:filename>")
@CheckUserSecurityAccessConditions
def Protect_Content(filename):
  return send_from_directory((os.path.join(os.path.dirname(__file__), 'ProtectedFolder')),filename)
Farzad Amirjavid
źródło