前言

之前自己写的flask使用gunicorn上线生产环境没有什么问题,但是最近搭建了一个现成的flask项目,当使用python直接运行时不会有问题,而使用gunicorn时则会出现一些问题。


部署过程

运行测试

这里使用pyenv创建了一个虚拟环境,并安装好依赖

pyenv virtualenv 3.9.6 freegpt
pyenv activate freegpt
pip install -r requirements.txt

下面是入口函数run.py

from server.app import app
from server.website import Website
from server.backend import Backend_Api
from json import load if __name__ == '__main__':
# Load configuration from config.json
config = load(open('config.json', 'r'))
site_config = config['site_config']
# Set up the website routes
site = Website(app)
for route in site.routes:
app.add_url_rule(
route,
view_func=site.routes[route]['function'],
methods=site.routes[route]['methods'],
) # Set up the backend API routes
backend_api = Backend_Api(app, config)
for route in backend_api.routes:
app.add_url_rule(
route,
view_func=backend_api.routes[route]['function'],
methods=backend_api.routes[route]['methods'],
)
# Run the Flask server
print(f"Running on port {site_config['port']}")
app.run(**site_config)
print(f"Closing port {site_config['port']}")

其中site_config.json文件如下:

{
"site_config": {
"host": "127.0.0.1",
"port": 1234,
"debug": false
},
"use_auto_proxy": false
}

意思是,运行flask服务于127.0.0.1:1234,只运行本地访问,后期我们需要搭建Nginx进行反向代理。

我们先使用python直接运行测试一下看能否跑起来以及能否正常访问。

python run.py

我们在服务器使用curl进行请求

curl 127.0.0.1:1234

数据返回正常,说明可以正常访问。


gunicorn搭建

Gunicorn是一个WSGI HTTP Server,是针对Python的、在Unix系统上运行的、用来解析HTTP请求的网关服务。

它的特点是:能和大多数的Python web框架兼容;使用简单;轻量级的资源消耗;高性能。

首先在当前虚拟环境下安装gunicorn

pip install gunicorn

然后我们使用gunicorn将flask项目跑起来,并且仅对本机开放,端口4444

gunicorn run:app -b 127.0.0.1:4444 --access-logfile access.log --error-logfile error.log &

使用ps命令可以看到当前已经成功在后台运行起来了

ps aux | grep gunicorn

踩坑

但是此时当我们再次使用curl访问127.0.0.1:4444时:

出现了404的错误。

我们查看gunicorn生成的日志文件:

# access.log
127.0.0.1 - - [13/Jul/2023:12:51:11 -0400] "GET / HTTP/1.1" 404 207 "-" "curl/7.76.1"

可以看到成功的请求到了我们的wsgi server,但是返回了404。在外网论坛上摸索了一番,问题出在了run.py上。

run.py文件中的所有代码都是写在if __name__ == "__main__":之下的,这在python语法中代表着主函数入口。

  • 当使用Python直接运行脚本时(例如:python run.py),if __name__ == '__main__'条件下的代码块会被执行,包括app.run()。这将启动Flask服务器,并让应用程序开始监听指定的主机和端口。
  • 当使用Gunicorn运行应用程序时(例如:gunicorn --bind 127.0.0.1:4444 run:app),if __name__ == '__main__'条件下的代码块不会被执行。因为Gunicorn实际上是将你的代码作为一个模块导入,而不是直接运行该代码。在这种情况下,Gunicorn会在内部处理Flask服务器的启动逻辑,并监听指定的主机和端口。也就因此自己在app.run(**kwargs)中设定的hostportdebug等参数也就失效了。

因此,无论是使用Python直接运行还是使用Gunicorn运行应用程序,app.run()只会在Python直接运行脚本时执行。而在使用Gunicorn运行时,if __name__ == '__main__'条件下的代码块将被跳过,包括app.run()。这是因为Gunicorn已经处理了服务器的启动逻辑。

因此,if __name__ == '__main__'条件的目的是为了确保在直接运行脚本时才执行特定的代码块,而在被导入为模块时跳过这些代码块。这样可以确保在使用Gunicorn启动应用程序时不会重复启动Flask服务器,并避免出现意外行为。


解决方案

既然已经知道了错误的逻辑,那么解决方法就很简单了,只要把除了app.run()的其他代码全部移出if __name__ == "__main__"即可。修改后的run.py如下:

from server.app import app
from server.website import Website
from server.backend import Backend_Api
from json import load # Load configuration from config.json
config = load(open('config.json', 'r'))
site_config = config['site_config']
# Set up the website routes
site = Website(app)
for route in site.routes:
app.add_url_rule(
route,
view_func=site.routes[route]['function'],
methods=site.routes[route]['methods'],
) # Set up the backend API routes
backend_api = Backend_Api(app, config)
for route in backend_api.routes:
app.add_url_rule(
route,
view_func=backend_api.routes[route]['function'],
methods=backend_api.routes[route]['methods'],
) if __name__ == '__main__':
# Run the Flask server
print(f"Running on port {site_config['port']}")
app.run(**site_config)
print(f"Closing port {site_config['port']}")

这样就可以保证python和gunicorn方式均可正常运行。

先kill掉之前正在运行的gunicorn,并重新启动

kill -9 1275864 1275865
gunicorn run:app -b 127.0.0.1:4444 --access-logfile access.log --error-logfile error.log &

可以看到现在请求127.0.0.1:4444已经正确响应了


Nginx反向代理

目前搭建的服务只能服务器自己访问到,下面我们通过nginx反向代理将其映射到对外的80端口

安装配置nginx就不多说了,下面讲讲配置文件的写法。其实很简单

vim /etc/nginx/nginx.conf
# nginx.conf
...
server {
listen 80;
server_name xxxxxxxx; # 此处填绑定的域名 location / {
proxy_pass http://localhost:4444;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
}
}
...

然后运行nginx即可

nginx -t
nginx

此时使用本机访问域名的80端口已可以正常访问了。

Flask结合gunicorn和nginx反向代理的生产环境部署及踩坑记录的更多相关文章

  1. [转]Nginx反向代理和负载均衡部署指南

    Nginx反向代理和负载均衡部署指南   1.        安装 1)         从Nginx官网下载页面(http://nginx.org/en/download.html)下载Nginx最 ...

  2. Nginx反向代理和负载均衡部署指南

    1.        安装 1)         从Nginx官网下载页面(http://nginx.org/en/download.html)下载Nginx最新版本(目前是1.5.13版本)安装包: ...

  3. Nginx反向代理腾讯云COS的一个坑

    版权声明:本文由黄希彤   原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/668639001484812620 来源:腾云 ...

  4. Nginx入门及如何反向代理解决生产环境跨域问题

    1.Nginx入门与基本操作篇 注:由于服务器是windows系统,所以本文主要讲解Nginx在windows下的操作. 首先下载Nginx 解压缩,我们所有的配置基本都在万能的 nginx/conf ...

  5. Nginx反向代理其他使用方式

    Nginx反向代理在生产环境中使用很多的. 场景1: 域名没有备案,可以把域名解析到香港一台云主机上,在香港云主机做个代理,而网站数据是在大陆的服务器上. 示例1: server { listen 8 ...

  6. Vue Nginx反向代理配置 解决生产环境跨域

    Vue本地代理举例: module.exports = { publicPath: './', devServer: { proxy: { '/api': { target: 'https://mov ...

  7. nginx 反向代理配置示例

    Nginx反向代理在生产环境中使用很多的. 场景1: 域名没有备案,可以把域名解析到香港一台云主机上,在香港云主机做个代理,而网站数据是在大陆的服务器上. server { listen ; serv ...

  8. Server 主机屋云服务器 宝塔面板 部署nginx反向代理的vue项目

    图文记录云服务器上部署需要nginx反向代理的vue项目: 一.先登录并购买云服务器,根据自己需求购买,此处不详细介绍: 二.登录后如下图,点击进入云服务器界面: 三.在云服务器界面点击管理,进入管理 ...

  9. Nginx反向代理实现Tomcat多个应用80端口访问

    应用背景 一般我们在开发时,一个工程里会有多个Web应用,比如一个前台一个后台,那我们就需要配置2个Tomcat服务器,比如一个是http://localhost:8080,一个是http://loc ...

  10. CORS跨域与Nginx反向代理跨域优劣对比

    最近写了一些关于前后端分离项目之后,跨域相关方案的基本原理和常见误区的帖子,主要包括CORS和Nginx反向代理.这两种方案项目中都有在用,各有优缺,关于具体使用哪种方案,大家的观点也不大一致,本文主 ...

随机推荐

  1. Java学习笔记05

    1. 方法概述 概念 ​ 方法(method)是程序中最小的执行单元. 注意: 方法必须先创建才可以使用,该过程称为方法的定义. 方法创建后并不是直接可以运行的,进行方法的调用才会执行. 2. 方法的 ...

  2. 开心档之MySQL 复制表

    MySQL 复制表 如果我们需要完全的复制MySQL的数据表,包括表的结构,索引,默认值等. 如果仅仅使用CREATE TABLE ... SELECT命令,是无法实现的. 本章节将为大家介绍如何完整 ...

  3. uniapp directive 在原生 wgt 包不生效 uniapp directive 不生效

    需求 根据权限编码禁用按钮 阻止当前 dom 绑定的点击事件,禁用状态(opacity 半透明?? 或者 display: none?? ) 尝试 开发环境用 Chrome 跑,一切正常,构建打包后去 ...

  4. taro-ui Calendar 修改星期开始时间为星期一(中国格式)

    官网Calendar文档:http://taro-ui.jd.com/#/docs/calendar 日历虽然兼容性很高,小程序也能使用,但扩展性并不高,如果需要更强的样式/自定义,需要复制部分源码到 ...

  5. HMS Core 6.10.0版本发布公告

    分析服务 ◆ 事件分析下新增商品订阅分析报告,帮助开发者了解应用内用户付费订阅概况,评估订阅付费价值: ◆ 营销分析.用户质量.转化分析以及过滤器中,新增广告系列/广告任务通过ID进行搜索的功能,通过 ...

  6. git仓库过渡,同时向两个仓库推送代码

    公司部门被大佬收购,产品项目迁移新公司仓库,过渡期间产品上线流程继续使用原公司的,新公司部署新系统后通过域名重定向逐渐将用户引流到新系统上完成切换,最后关闭原公司系统及上线流程. 过渡期间新功能代码需 ...

  7. PHP前后端交互

    PHP是现如今十分流行的轻量级语言,经常用来做应用的后端开发,其特点是语法简单,十分容易上手.除了单独做后端,PHP还能够将程序嵌入到HTML文件中执行,非常容易实现简单的前后端交互.而且PHP的运行 ...

  8. Git&GitHub简介与入手(二)

    四.GitHub 1.建账号,仓库 https://github.com/  用邮箱在官网注册: 增加远程库的地址取别名为origin,push为推送,fetch为取回: 2.推送操作 将本地当前所在 ...

  9. 2022-05-04:比如,str = “ayxbx“, 有以下4种切法 : a | yxbx、ay | xbx、ayx | bx、ayxb | x, 其中第1、3、4种切法符合:x和y的个数,至少在

    2022-05-04:比如,str = "ayxbx", 有以下4种切法 : a | yxbx.ay | xbx.ayx | bx.ayxb | x, 其中第1.3.4种切法符合: ...

  10. 2022-04-07:给定一个只由‘a‘和‘b‘组成的字符串str, str中“ab“和“ba“子串都可以消除, 消除之后剩下字符会重新靠在一起,继续出现可以消除的子串... 你的任务是决定一种消除的

    2022-04-07:给定一个只由'a'和'b'组成的字符串str, str中"ab"和"ba"子串都可以消除, 消除之后剩下字符会重新靠在一起,继续出现可以消 ...