Nginx反向代理多个应用时,通过BluePring使Flask支持二级路径(URL前缀)

9 篇文章 0 订阅
5 篇文章 0 订阅
1. 预期

最近陆续基于Nginx,完成了三个应用的部署:

理所当然冒出来一个想法就是把它们一并启起来,而且云服务器上除了http的80和https的443以外,不要增加更多的端口。预期的效果如下:

  1. 应用A和应用B都是我自己开发的Flask应用,共用443端口,通过不同的URL前缀实现区分
  2. 应用C是别的开发团队的PHP开源应用,使用80端口,不做改变
  3. 输入https://域名(或主机IP地址)根路径时,打开一个导航页面,3个链接指向上述三个应用

例如,输入带SSL的URL地址:https://127.0.0.1,打开这样一个导航页面:
在这里插入图片描述
点击“微信小应用服务”,即跳转到带SSL的URL地址:https://127.0.0.1/uu,打开应用A的页面:
在这里插入图片描述
点击“微信小应用服务”,即跳转到带SSL的URL地址:https://127.0.0.1/uu/ocr,打开应用B的页面:
在这里插入图片描述
点击“微信小应用服务”,即跳转到不带SSL的URL地址:http://127.0.0.1,打开应用C的页面:
在这里插入图片描述

2. 配置

虽然应用A和B实际上是同一个Flask应用,不过在A的系列页面中没有指向B的链接,所以可以认为在“应用层面”上是两个应用。不过不管是一个还是两个,并不影响本文的重点:

本文的重点是:上面的想法理论上非常简单,这正是Nginx反向代理的长项,只要在nginx.conf配置文件中设置多个location块,分别指向不同URL前缀就可以了。
ngnix.conf配置如图:
在这里插入图片描述
配置文件中添加了“add_header X-debug-message”,这样可以方便的在浏览器控制台看到我们走的是哪一条配置。如下图所示:
在这里插入图片描述

3. 问题

然而实际部署起来还是遇到了一些困难,主要是无论是应用A和应用B,只要 location 不指向 / ,就无法在Flask中定位出正确的路由。以应用B为例,Nginx传给后台Flask的URL是:https://127.0.0.1/uu/ocr,但是Flask中的路由无法处理多出来的/uu

# OCR测试
@webapp.route('/ocr', methods=['POST', 'GET'])
def ocr():
    basepath = os.path.dirname(__file__)  # 当前文件所在路径
    print(request.method)
    if request.method == 'POST':
        f = request.files['file']
        upload_path = os.path.join(basepath, 'static/uploads', secure_filename(f.filename))  # 注意:没有的文件夹要先创建
        f.save(upload_path)
        return redirect(url_for('profile.ocr_result', pic_name=f.filename))
    else:
        return render_template('ocr.html')

当然将所有路由标签都加上前缀也能算是一种“笨办法”,正道还是由Flask的BluePrint来解决。

4. 用BluePrint实现URL前缀功能

先给出一个最简单的bp例子程序:

# 使用蓝图建立统一路由前缀,便于nginx部署多应用
# 通常这句话写在routes.py中
bp = Blueprint('blueprint', __name__, url_prefix='/uu/vv', 
				static_folder='', static_url_path='')

# 用蓝图进行路由标记
@bp.route("/")
def index_page():
  return "This is website root"

# 用蓝图进行路由标记
@bp.route("/about")
def about_page():
  return "This is a website about page"


app = Flask(__name__)
# 应用注册蓝图
# 通常这句话写在__init__.py中
app.register_blueprint(bp)

上面这个简单的例子可以正常运行,但是在Flask的项目中,需要考虑到有SQLAlchemy的数据库模块,还有LoginManager用户登录模块,很容易引起循环import。所以在实际使用的时候,需要考虑将这些公共组件进行模块化处理。

5. 用BluePrint将程序中的公共组件模块化

对于 SQLAlchemy:
原本是在 __init__.py 中同时定义 db 并与 webapp 关联:webapp.SQLAlchemy(db)。但是这样会造成在 routes.py 中from app import db,同时又在 __init__.py 中from app.routes import bp,这样就造成了循环导入。
可以改为在 models.py 中定义db = SQLAlchemy(),在 __init__.py 中通过 db.init_app(webapp) 进行 db 与 webapp 关联。在 routes.py 和 __init__.py 中from app.models import db

对于 LoginManager:
原本是在 __init__.py 中同时定义 login 并与 webapp 关联:webapp.LoginManager(login)
可以改为在 models.py 中定义 login = LoginManager() ,在 __init__.py 中from app.models import login,并通过 login.init_app(webapp) 进行 login 与 webapp 关联。

6. url_for处理

在后台python代码,和html模板文件中的所有 url_for(function_name),全部需要改成 url_for(bp.function_name)

7. 静态资源处理

以为一切妥当以后,发现静态资源访问不了。查了Blueprint的构造函数,发现参数static_folder和static_url_path的缺省值都是None,改成空字符串’'后,又可以看到静态资源了。

所有的源码在这里,欢迎下载并提出宝贵意见 : - )

【参考资料】
如何为所有Flask路由添加前缀?
python flask使用blueprint
flask+SQLAlchemy使用blueprint模块化
有关flask的static文件夹,如何设置在blueprint的根目录下呢

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

皓月如我

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值