Flask和React路由转换

42

我正在使用React构建Flask应用,但遇到了路由问题。

后端负责作为API,因此一些路由看起来像:

@app.route('/api/v1/do-something/', methods=["GET"])
def do_something():
    return something()

以及通往React的主要路径:

@app.route('/')
def index():
    return render_template('index.html')

我在 React 应用中使用了 react-router,一切都工作得很好,react-router 带我去了 /something 并渲染了视图,但是当我在 /something 上刷新页面时,Flask 应用将处理这个请求,我收到了 Not Found 错误。

最好的解决方案是什么?我考虑将所有没有调用 /api/v1/... 的请求重定向到 /,但这并不理想,因为我会得到我的应用程序主页,而不是渲染后的React视图。


2
如果您不希望后端处理URL,则最快且最简单的方法是不使用HTML5历史记录API。禁用它将导致哈希bang URL,例如/#/something,并且重新加载它们将始终触发后端上的/视图。否则,您需要在后端处理请求或将其重定向到React应用程序,然后分析请求并在请求的URL不是/时触发位置更改。 - sthzg
那看起来像是某种解决方案,谢谢! - knowbody
5
我不认为这是一个好的解决方案。现在已经是2015年了,你应该使用History API。 - Dan Abramov
@DanAbramov 没错,但是怎么做呢? - knowbody
还有一种方法 - 您可以在.htaccess文件中编写重写语句,以便每次特定的#something通过react-router而不是flask。如果URL基于某些模式,则这可能是一种有效的解决方案,否则就是浪费时间。 - Pralhad Narsinh Sonar
5个回答

39

我们在这里使用了catch-all URL

from flask import Flask
app = Flask(__name__)

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def catch_all(path):
    return 'You want path: %s' % path

if __name__ == '__main__':
    app.run()

你还可以更进一步,重用Flask routing系统将path与客户端匹配到相同的路由,以便在HTML响应中嵌入客户端所需的JSON数据。


1
如果所有路由都将指向catch all函数,那么当我从前端进行ajax请求调用时,如何区分后端api路由和react路由? - shangsunset
7
请先注册API路由,然后再注册“捕获所有”路由,以确保API路由具有优先权。 - Dan Abramov
这里有完整的示例吗?这里的代码没有像上面的示例那样进行任何索引渲染,我一直无法将两者结合起来使其正常工作。 - juanitogan
6
找到了。在搞清楚文档不够清晰的 Flask 参数之前,我无法使 @app.route('/<path:path>') 匹配任何内容。设置 static_url_path="" 是不好的。最终我使用了 static_url_path="/public", static_folder="../public",然后返回一个静态文件:return app.send_static_file("index.html"),其中硬编码了 "/public/..." 的 URL。此外,请查看:https://www.reddit.com/r/reactjs/comments/42pn95/reactrouter_and_flask_404/(不是我的帖子)。 - juanitogan
这是我使用了一段时间的解决方案,直到我需要使用 React.lazy 将我的 bundle 分成几个部分。React.lazy 需要从 path 获取 bundle 部分,而不是 flask 使用的静态目录。对此有什么想法吗? - Jason
你好 @Jason,React.lazy 有什么问题吗?我们正在尝试采用这种方法,我正在研究所有的优缺点。谢谢。 - logeekal

6
也许可以作为之前回答的扩展。这对我解决了问题。
from flask import send_from_directory

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def serve(path):
     path_dir = os.path.abspath("../build") #path react build
     if path != "" and os.path.exists(os.path.join(path_dir, path)):
         return send_from_directory(os.path.join(path_dir), path)
     else:
         return send_from_directory(os.path.join(path_dir),'index.html')

你不能用普通的path_dir替换空的os.path.join(path_dir)吗? - TheDiveO

4

由于某些原因,通配符URL对我无效。我发现使用 Flask 404 处理程序得到的结果完全相同。它会看到 URL 并将其传递给 React,在那里你的路由器会处理它。

@app.errorhandler(404)   
def not_found(e):   
  return app.send_static_file('index.html')

这个很棒!谢谢分享! - Sundios

1

我只是想通知您,对于我来说,处理错误404和渲染模板都非常完美。

@app.errorhandler(404)
def not_found(e):
    return render_template("index.html")

0

我必须同时结合 catch-all 和 404 处理程序才能使其正常工作。我正在子路径中托管一个 React 应用程序,并使用其自己的重定向处理程序来自 react-router。

@app.route('/sub-path',  defaults={'path': 'index.html'})
@app.route('/sub-path/<path:path>')
def index(path):
    return send_from_directory('../react-dir/build', path)

@app.errorhandler(404)
def not_found(e):
  return send_from_directory('../react-dir/build','index.html')

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