django+uwsgi+nginx 前后端分离部署配置

东围居士 2021-10-26 15:23:49
后端 nginx django uWSGI django+uwsgi+nginx

本文仅用于记录自己的踩坑过程,避免以后有同样需求的时候没思路

开发环境

后端部分

  • django==3.2.8
  • sqlite3==3.36.0

前端部分

  • vue==2.6.14
  • elementui (版本不知道)
  • axios (版本不知道)

服务器环境

  • uwsgi==2.0.20
  • nginx==1.20.1

所有的代码文件都位于 /myweb 目录下,该目录的结构如下:

这里的/myweb/backend/daily_exercise/exercise文件夹是使用 djangoadmin startproject 时自动创建的,/myweb/backend/daily_exercise/daily目录则是使用 python manage.py startapp 命令创建的

后端部分位于/myweb/backend/daily_exercise,前端部分位于/myweb/frontend/daily_exercise

后端使用 uwsgi 进行部署,加上 nginx 进行转发以避免跨站问题,前端只用 nginx 部署。

后端部署:uwsgi 部署 django

先安装 uwsgi

pip install uwsgi

然后在任意地方创建一个 uwsgi 的配置文件。本例中叫 uwsgi.ini,位于 /myweb/backend/ 目录下,虽然 /myweb/backend/daily_exercise/ 目录下还有一个同名的 uwsgi.ini,但是在服务器端部署用不到这个文件,这个文件是在本地部署时候用到的,因为在服务器上的 /myweb/backend/daily_exercise/ 目录被我设置成了 git 的远程仓库,所以在本地提交的时候也把这个配置文件提交上来了。
/myweb/backend/uwsgi.ini文件内容如下

[uwsgi]
http=:8000
master=True
processes=4
threads=4
chdir=/myweb/backend/daily_exercise
wsgi-file=/myweb/backend/daily_exercise/exercise/wsgi.py
vacuum=True
max-requests=5000
daemonize=/var/log/uwsgi/daily_exercise.log
pidfile=/tmp/daily_exercise.pid
py-autoreload=1

其中,要注意的是以下几个参数:

  • http 表示程序将要运行在哪个端口。本例是 8000
  • chdir 是 django 项目的根目录地址,也就是 manage.py 文件所在的目录
  • wsgi-file 是项目中 wsgi.py 文件地址。这里可以写成是相对地址,也可以是绝对地址
  • daemonize 指明 django 项目运行时产生的日志文件位置
  • pidfile 指定 django 项目运行时将要产生的进程文件名称和位置
  • py-autoreload 指定是否自动重载。如果等于 1,则在代码更新后,uwsgi 服务会自动重载。否则需要手动重载(命令是:uwsgi --reload /tmp/daily_exercise.pid)

然后执行:

uwsgi uwsgi.ini

即可部署完毕。可以查看 /var/log/uwsgi/daily_exercise.log 的内容,检查是否有报错,如果没有报错就没问题。同时也可以直接打开 http://服务器id:8000 (或其它在 django 中定义的有效路径)来观察部署结果。

前端部署:nginx 部署纯前端项目

如果系统中没有安装 nginx,需要先安装,网上有很多教程。

安装完后,修改 /etc/nginx/nginx.conf 配置文件

http {
server {
localhost /frontend/daily {
alias /myweb/frontend/daily_exercise;
}
}
}

如上,在默认的 http > server 内加入以下三行即可。

 localhost /frontend/daily {
alias /myweb/frontend/daily_exercise;
}

其中 localhost 后面的 /frontend/daily 是自定义的访问地址,访问时在服务器地址后面加上这个自定义地址即可,如:http://服务器IP/frontend/daily

至此,前端、后端分别部署完毕。但是由于 django 部署使用的是 8000 端口,前端部署使用的是默认的 80 端口,前端发请求时会有跨站(CROS)问题。

比如,前端需要向后端接口 http://localhost:8000/daily/api 发请求获取数据,则在前端会出现跨站请求的错误。

一个解决的思路是,前端只向默认的 80 端口发请求,由 nginx 转发到 8000 端口,就不会有这个问题。

配置 nginx 解决跨站问题

同样简单,在前述的 nginx 配置文件 /etc/nginx/nginx.conf 文件中加上转发的规则,同样是在 http -> server 下添加:

locahost /daily/api {
proxy_pass http://127.0.0.1:8000/daily/api;
proxy_redirect default;
}

这样,当在浏览器中打开 http://服务器IP/daily/api 时,nginx 会转发至 http://127.0.0.1:8000/daily/api 这个地址。

当然以上是硬编码的方式,并不是最优解,网上还有其它方式可以更加灵活地实现这种不同端口之间的转发。

别忘了修改 django 项目中的跨站访问配置

需要安装 django 的 cros 插件:

pip install django-cros-headers

修改 /myweb/backend/daily_exercise/exercise/settings.py 文件,添加以下内容

CORS_ORIGIN_WHITELIST = (
'http://127.0.0.1:8000',
'http://localhost:8000',
'http://localhost',
'http://127.0.0.1',
)
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_METHODS = (
'DELETE',
'GET',
'POST',
'PUT',
)
CORS_ALLOW_HEADERS = (
'XMLHttpRequest',
'X_FILENAME',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
'Pragma',
)

再修改同文件下的MIDDLEWARE变量,增加corsheaders.middleware.CorsMiddleware

允许跨站(CROS问题解决)后,在前端代码中可以使用相对路径来访问后端的接口(这样可以在没有配置 nginx 转发的本地环境中也能正常运行),例如:

解决 sqlite3 版本过低的问题

在本地(或服务器)使用 python manage.py runserver 时,如果 sqlite3 版本过低,项目是运行不起来的,会 sqlite3 版本过低的错误,因为 django3 要求 sqlite3 的版本要大于等于 3.9.0,可以先按网上的教程升级系统的 sqlite3

sqlite 官网中提供的最新版本应该是远高于 3.9 的。
升级完后,使用 python manage.py runserver 命令执行应该没问题了,但是使用 uwsgi 部署时,很可能依然还会报版本过低的错误,如下,可在uwsgi.ini文件内指定的/var/log/uwsgi/daily_exercise.log文件中看到错误:

估计是程序找不到最新安装的 sqlite3,原因不明,也未找到解决办法,按网上说的添加参数到 bash_profile 无效,使用参数重新编译 python 也没有作用。

最终我是直接修改 django 中的判断语句来避开这个检测的。如上图中的黄色框部分,修改这个文件里面的check_sqlite_version函数,如下:

上图是修改后的,修改前黄框中应该是(3, 9, 0)

至此,问题解决,部署完毕!

版权声明
本文为[东围居士]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/wuzhiblog/p/15465107.html

  1. It's time for everyone to see your blog written in Django (including deployment tutorial video)
  2. Python扩展速记符 要求用for循环,if语句
  3. Python擴展速記符 要求用for循環,if語句
  4. Le sténographe d'extension Python nécessite une boucle pour, si instruction
  5. Python+人工智能就业班v5.0wumi
  6. python编程技术的题目,希望能得到解答
  7. Pandas determines the header row dynamically
  8. 关于#python#的问题:模拟登陆后能获取到cookie,就是cookie一天就过期
  9. pandas为dataframe添加新的数据行(rows)、在dataframe后面纵向添加一行数据(数据为列表list形式)、列有不匹配将会使用NA值进行填补
  10. pandas使用组合条件筛选、过滤数据行
  11. 热烈祝贺1024,求解Python3.10闪退问题
  12. Python基础题练习题库有没呢?
  13. python构建神经网络,正向和反向传播
  14. python爬虫输入数字翻页才成功,用变量代替不成功,为什么?
  15. 【Python 爬虫】 2、HTTP基本原理
  16. 【Python 爬虫】 1、爬虫基础概念
  17. Python中如何用find函数计数?
  18. 一文搞懂Python装饰器
  19. python数据结构之递归
  20. 关于#python#的问题:为什么这个open函数会报错
  21. Python:多输入数字求和(Python 程序控制结构)
  22. python忽略警告
  23. Python多维数组问题(编写程序统计成绩)
  24. 一步一步展示并总结Python的异常【建议收藏】
  25. Python中奇葩的round函数!
  26. 总结一下Python的模块加载解析
  27. 保姆级指导给Python库创建桌面快捷方式【赶紧收藏】
  28. 多图速成Python基础语法下篇【万字建议收藏】
  29. Python 命令行工具辅助getopt使用解析!
  30. 【python种子项目ppc】保姆级别指导给项目添加测试
  31. 【python种子项目ppc】一行代码生成项目与开发详细指导
  32. 保姆级教程带你开发优质的Python库之下篇【种子项目】
  33. 保姆级教程带你开发优质的Python库之中篇【命令行发行】
  34. 保姆级教程带你开发优质的Python库之上篇【建议收藏】
  35. python列表自动计算总分程序
  36. 某企业职工的月薪问题python 求解 不知道自己哪里写错了
  37. Python中外部函数对class类中的属性的调用
  38. 朋友股票亏惨了,我一怒用Python爬取了证券最新数据
  39. 习题8和9怎么写(Python基础)
  40. python数据分析,求任务4,5
  41. Python 的 f-strings,远比你想象的要强大!
  42. django channels channel_layer.group_send 造成内存溢出
  43. 判断天数问题用python 解决 不知道自己哪里写错了 一直显示invalid syntax
  44. OpenCV-Python对比度受限的自适应直方图均衡CLAHE知识介绍
  45. pandas 如何读取指定位置和数量的列
  46. django后台模型中的文件字段,上传后再下载时提示找不到页面
  47. 关于#python#的问题:使用requests请求网页时出现网页过期是怎么回事啊,cookie也没有过期,也提交了头文件的
  48. Pycharm开发Django项目外键和表关系
  49. [PYTHON][BAT][SHELL] 常见易忘 python、bat、shell 脚本操作汇总(持续更新)
  50. django学习-34.【多对多】表关系对应的完整业务操作
  51. 在GitHub上下载了一个python代码,看readme很疑惑,求解答
  52. 怎么用python程序做这问题
  53. python程序设计实验4-程序的异常处理
  54. 【Python每日作业】Day7: 如何在一个表达式里面合并两个字典?
  55. Python Type Hints 从入门到实践
  56. pyinstaller 打包 exe 无法在没有装python的电脑上运行,提示如下。。
  57. 关于Python中的Image. open函数的使用出现的问题
  58. 代码0基础先学哪个?WEB、python、JAVA
  59. Python基于PCANBasic二次开发使用方法
  60. Python实现相加为奇数则用户赢,如果并且用户能自行选择退出游戏,且计算他们的分数