Python(Flask)提供Angular项目的index.html文件

8

有人知道如何使用Flask提供Angular单页应用程序的服务吗?

我在提供默认路由'/'时遇到了麻烦,这个路由应该加载index.html和相关组件。以下是我的Flask函数:

@app.route('/')
def hello_world():
    return send_file('templates/dist/templates/index.html')

当我访问localhost:5000时,会出现一个空的Chrome浏览器窗口:

Empty Chrome window with Angular / Flask

并且在Chrome的开发控制台中会出现以下错误:

enter image description here

这是应该在Chrome中显示的内容:

enter image description here

我认为这些错误是因为Flask不知道在哪里找到支持文件以呈现Angular组件。按照Angular的快速入门教程中的指示,我的index.html大部分为空,app-root作为HTML body元素的占位符。
<body>
  <app-root></app-root>
<script type="text/javascript" src="runtime.js"></script><script type="text/javascript" src="polyfills.js"></script><script type="text/javascript" src="styles.js"></script><script type="text/javascript" src="vendor.js"></script><script type="text/javascript" src="main.js"></script></body>

有人知道如何告诉Flask让Angular渲染页面吗?
3个回答

10

为了简化设置,请考虑使用Angular CLI在构建过程中将所有文件放置在分发目录中,即通过在angular.json中指定outputPath。 您可以使用angular.json的assets部分在构建过程中移动Python文件。

angular.json

"your-project": {
  "root": "your-project-directory",
  "sourceRoot": "your-project-directory/src",
  "projectType": "application",
  "architect": {
    "build": {
    "builder": "@angular-devkit/build-angular:browser",
    "options": {
      "outputPath": "dist",
      "index": "your-project-directory/src/index.html",
      "main": "your-project-directory/src/main.ts",
      ...

      "assets": [
        {
          "glob": "**/*",
          "input": "your-project-directory/src/assets/",
          "output": "assets"
        },
        {
          "glob": "**/*",
          "input": "your-project-directory/src/python/",
          "output": "."
        }



dist 目录的顶层中,将带有基本 Flask 设置的 main.pyindex.html 放置在一起。请注意使用 static_proxy 来确保支持文件得到服务。

main.py

from flask import Flask, send_from_directory

app = Flask(__name__)


@app.route('/<path:path>', methods=['GET'])
def static_proxy(path):
  return send_from_directory('./', path)


@app.route('/')
def root():
  return send_from_directory('./', 'index.html')


if __name__ == '__main__':
  # This is used when running locally only. When deploying use a webserver process 
  # such as Gunicorn to serve the app.
  app.run(host='127.0.0.1', port=8080, debug=True)


@app.errorhandler(500)
def server_error(e):
  return 'An internal error occurred [main.py] %s' % e, 500

请注意,从Angular 8开始,需要严格的MIME类型。对于以.js结尾的每个路径,您的static_proxy应该为send_from_directory调用添加mimetype="application/javascript"关键字参数。否则,您将得到一个空页面和许多错误:“Failed to load module script: The server responded with a non-JavaScript MIME type of ""。根据HTML规范,模块脚本要求严格的MIME类型检查。” - Robin De Schepper
@RobinDeSchepper 我一直在寻找如何做到这一点,但我找不到一个合适的答案。你能给我们举个例子吗? - Ajmal
1
@Ajmal 如果路径以“.js”结尾:return send_from_directory('./', path, mimetype="application/javascript") - Robin De Schepper
这在路由方面并不起作用。如果您从根开始使用应用程序并跟随链接,则路由将起作用,但是如果您直接在浏览器中输入Angular路由,则只会显示404错误。 - Ben Robinson

6

这是一个老问题,但接受的答案对我不起作用。因此,这里是我的解决方案,适用于Angular路由:


我的文件夹结构:

/angular
    /src
    angular.json
    ... angular project files
/public
    index.html
    ... angular build files
/venv
server.py

在我的 angular.json 文件中,我将 outputPath 更改为实现上述结构:
"outputPath": "../public"

server.py 文件中:
import os.path

@app.route("/custom-endpoint")
def custom_endpoint_handler():
    return jsonify(myKey="myValue")


# Serving static files
@app.route('/', defaults={'path': ''})
@app.route('/<string:path>')
@app.route('/<path:path>')
def static_proxy(path):
    if os.path.isfile('public/' + path):
        # If request is made for a file by angular for example main.js
        # condition will be true, file will be served from the public directory
        return send_from_directory('public', path)
    else:
        # Otherwise index.html will be served,
        # angular router will handle the rest
        return app.send_static_file("index.html")

注:我对 Flask 还不熟悉。如果有任何错误,欢迎提出改进或修复。


点赞。这很简单,对我有用,只需进行微小的调整,即在else块中也执行return send_from_directory(FE_BUILD_DIR, "index.html"),因为index.html也在该构建目录(在您的示例中为“public”)中...但是,无论如何,非常感谢。 - Suman Barick
路径变量中有什么内容? - undefined

0
如 Flask docs 中所述:

只需在您的包或模块旁边创建一个名为 static 的文件夹,它将在应用程序的 /static 路径下可用。

因此,如果您在使用模板:

templates/dist/templates/index.html
static/ # set static folder there

或者,根据您的应用程序排序方式而定:

templates/dist/static/ # set static folder there

看看他们如何在文档中对应用程序进行排序:

/application.py
/templates
    /hello.html

或者如果你使用模块文件夹:

/application
    /__init__.py
    /templates
        /hello.html

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接