Tệp tĩnh trong Flask - robot.txt, sitemap.xml (mod_wsgi)


94

Có giải pháp thông minh nào để lưu trữ các tệp tĩnh trong thư mục gốc của ứng dụng Flask không. robots.txt và sitemap.xml dự kiến ​​sẽ được tìm thấy trong /, vì vậy ý ​​tưởng của tôi là tạo các tuyến đường cho chúng:

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

Phải có cái gì đó tiện hơn :)

Câu trả lời:


78

Cách tốt nhất là đặt static_url_path thành url gốc

from flask import Flask

app = Flask(__name__, static_folder='static', static_url_path='')

Điều đáng nói là static_folder không nhất thiết phải nằm trong thư mục dự án. ví dụ: static_folder = '/ app / ui' là được.
ashic

66

@vonPetrushev nói đúng, trong quá trình sản xuất, bạn sẽ muốn cung cấp các tệp tĩnh qua nginx hoặc apache, nhưng để phát triển, thật tuyệt khi môi trường phát triển của bạn đơn giản có ứng dụng python của bạn cũng cung cấp nội dung tĩnh nên bạn không phải lo lắng về việc thay đổi cấu hình và nhiều dự án. Để làm điều đó, bạn sẽ muốn sử dụng 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')
    })

Ví dụ này giả định rằng các tệp tĩnh của bạn nằm trong thư mục "tĩnh", hãy điều chỉnh để phù hợp với môi trường của bạn.


1
CẢM ƠN! Đây là những gì tôi cần! Tôi đang tìm cách làm điều này cho heroku sản xuất của mình. Xem câu trả lời trên chủ đề sau: flask.pocoo.org/mailinglist/archive/2012/2/22/…
David

2
Lưu ý - hiện có một cách dễ dàng hơn để xử lý vấn đề này. Kiểm tra câu trả lời của tôi.
Sean McSomething

1
Có cách nào để SharedDataMiddleware chỉ giải quyết '/' thành index.html hoặc tương tự không?
gromgull

63

Câu trả lời rõ ràng nhất cho câu hỏi này là câu trả lời cho câu hỏi (giống hệt nhau) này :

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:])

Tóm lại:

  • như David đã chỉ ra, với cấu hình phù hợp, bạn có thể phân phát một vài tệp tĩnh thông qua sản phẩm
  • tìm kiếm /robots.txt sẽ không dẫn đến chuyển hướng đến /static/robots.txt. (Trong câu trả lời của Seans, nó không rõ ràng ngay lập tức làm thế nào nó đạt được.)
  • việc thêm các tệp tĩnh vào thư mục gốc ứng dụng là không sạch
  • cuối cùng, giải pháp được đề xuất trông sạch hơn nhiều so với cách tiếp cận thêm phần mềm trung gian:

22

Mặc dù đây là một câu hỏi đã được trả lời cũ, nhưng tôi đang trả lời câu hỏi này vì bài đăng này xuất hiện khá cao trong kết quả của Google. Mặc dù nó không được đề cập trong tài liệu, nhưng nếu bạn đọc tài liệu API cho phương thức khởi tạo đối tượng Ứng dụng Flask, nó sẽ được đề cập. Bằng cách truyền tham số được đặt tên static_foldernhư sau:

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

... bạn có thể xác định các tệp tĩnh được cung cấp từ đâu. Tương tự, bạn có thể xác định a template_folder, tên của bạn static_url_path.


@chmike có, nó mặc định là /staticnhưng bạn có thể thay đổi điều đó bằng cách ghi đè static_url_path.
Sean McSomething

Điều này đúng nhưng các câu trả lời khác linh hoạt hơn. Điều này bị hạn chế bởi thực tế là nó chỉ có thể phục vụ một đường dẫn thư mục.
Thomas Dignan

Đây không phải là câu trả lời cho câu hỏi ban đầu.
Paolo Casciello

2
Nếu bạn đặt static_url_path thành "", bạn có thể cung cấp tệp từ /.
Beau,

Điều này buộc Flask phân phát các tệp tĩnh. Điều gì sẽ xảy ra nếu bạn muốn nginx hoặc apache phục vụ chúng?
Markon

15

Việc cung cấp các tệp tĩnh không liên quan gì đến ứng dụng nhằm cung cấp nội dung động. Cách chính xác để phân phát tệp tĩnh phụ thuộc vào máy chủ bạn đang sử dụng. Rốt cuộc, khi bạn thiết lập và chạy ứng dụng của mình, bạn sẽ cần phải liên kết nó với một máy chủ web. Tôi chỉ có thể nói về httpd apache, vì vậy cách phân phát tệp tĩnh được xác định trong máy chủ ảo mà bạn đang ràng buộc với ứng dụng của mình thông qua mod-wsgi. Đây là hướng dẫn sẽ chỉ cho bạn cách phân phát sơ đồ trang web, robots.txt hoặc bất kỳ nội dung tĩnh nào: http://code.google.com/p/modwsgi/wiki/QuickConfigurationGuide#Mounting_At_Root_Of_Site


Đó là câu trả lời mà tôi đang tìm kiếm. Cảm ơn!
biesiad

1
Một ứng dụng có nghĩa là cung cấp nội dung, một số động và một số tĩnh.
Dem Pilafian

14

Một cách khác để gửi tệp tĩnh là sử dụng quy tắc nhận tất cả như sau:

@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()

Tôi sử dụng điều này để cố gắng giảm thiểu thiết lập khi phát triển. Tôi lấy ý tưởng từ http://flask.pocoo.org/snippets/57/

Hơn nữa, tôi đang phát triển bằng cách sử dụng flask trên máy độc lập của mình nhưng triển khai với Apache trong máy chủ sản xuất. Tôi sử dụng:

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()

1
Lưu ý - hiện có một cách dễ dàng hơn để xử lý vấn đề này. Kiểm tra câu trả lời của tôi.
Sean McSomething

Cách tuyệt vời nếu bạn cần phục vụ nhiều đường dẫn!
Thomas Dignan

6

Điều này có thể đã được thêm vào từ khi câu hỏi này được hỏi, nhưng tôi đã xem qua "helpers.py" của flask và tôi tìm thấy 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.
'''

... tham chiếu đến flask.send_file:

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

... có vẻ tốt hơn để kiểm soát nhiều hơn, mặc dù send_from_directory chuyển trực tiếp ** các tùy chọn đến send_file.


3

Từ tài liệu tại đây: http://flask.pocoo.org/docs/quickstart/#static-files

Các ứng dụng web động cũng cần các tệp tĩnh. Đó thường là nơi xuất phát các tệp CSS và JavaScript. Lý tưởng nhất là máy chủ web của bạn được cấu hình để phục vụ chúng cho bạn, nhưng trong quá trình phát triển, Flask cũng có thể làm điều đó. Chỉ cần tạo một thư mục được gọi là tĩnh trong gói của bạn hoặc bên cạnh mô-đun của bạn và nó sẽ có sẵn tại / static trên ứng dụng.

Để tạo URL cho phần đó của URL, hãy sử dụng tên URL 'tĩnh' đặc biệt:

url_for ('static', filename = 'style.css')

Tệp phải được lưu trữ trên hệ thống tệp dưới dạng static / style.css.


0

Tôi cũng đang gặp tình huống khó xử tương tự. Đã thực hiện một số tìm kiếm và tìm thấy câu trả lời của tôi (MHO):

Cũng có thể trích dẫn từ tài liệu

Các ứng dụng web động cũng cần các tệp tĩnh. Đó thường là nơi xuất phát các tệp CSS và JavaScript. Lý tưởng nhất là máy chủ web của bạn được cấu hình để phục vụ chúng cho bạn, nhưng trong quá trình phát triển, Flask cũng có thể làm điều đó . Chỉ cần tạo một thư mục được gọi là tĩnh trong gói của bạn hoặc bên cạnh mô-đun của bạn và nó sẽ có sẵn tại / static trên ứng dụng.

IMHO: Khi ứng dụng của bạn được đưa vào sản xuất , việc phân phát tệp tĩnh phải được (hoặc lý tưởng là) được định cấu hình trên máy chủ web (nginx, apache); nhưng trong quá trình phát triển , Flask đã cung cấp nó để phục vụ các tệp tĩnh. Điều này là để giúp bạn phát triển nhanh chóng - không cần thiết lập máy chủ web và những thứ như vậy.

Hy vọng nó giúp.


0

Thử cái này:

@app.route("/ProtectedFolder/<path:filename>")
@CheckUserSecurityAccessConditions
def Protect_Content(filename):
  return send_from_directory((os.path.join(os.path.dirname(__file__), 'ProtectedFolder')),filename)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.