1.服务器选择原因:
uWSGI web服务器+Django其实也可以满足web服务器的要求,那么再接上nginx web服务器的原因?
首先Nginx服务器处理静态网页的能力特别强,起码比uWSGI web服务器好。所以可以两个服务器结合,做好动静服务的分离。即是Nginx提供静态服务,uWSGI服务器+Django提供动态服务,这样可以大大的提高响应效率。
2.安装配置uWSGI服务:
2.1安装uWSGI:
pip install uWSGI
2.2 终端命令启动uwsgi服务
Django应用可以单独跑起来(Django也带有web服务功能,但是比较差,可以验证开发)
Django 起服务的命令如下:python3 manage.py runserver 0.0.0.0:9000,如果这个可以通过浏览器验证通过,说明自己开发服务端程序没问题。
在之前验证通过的前提下,在Django项目目录中,执行一下命令,验证uwsgi服务器。
uwsgi --http 0.0.0.0:9000 --file form_demo/wsgi.py --static-map=/static=static
--file form_demo/wsgi.py: Django的form_demo项目名称,wsgi.py指定协议的名称即是wsgi协议。
--static-map=/static=static: 静态文件,可以不写。在浏览器刷新时会找不到。
以上是命令行启动,实际项目中更多的使用配置文件启动。
2.3使用配置文件启动uWSGI [ini 格式]
如下文件uwsgi.ini
[uwsgi]
#项目目录,根据自己项目来定
chdir=/data/Project/python/django_project/form_demo
#启动uwsgi的用户名和用户组
uid=root
gid=root
#指定项目的application
moudle=for_demo.wsgi
#指定sock的文件路径,相对路径有时会出现无法创建文件的情况.
socket=/data/Project/python/django_project/script/uwsgi.sock
#http = :8080 # 如果需要同时提供HTTP服务(如直接对外),此处配合nginx,未用
#启用主进程
master=true
#进程个数
worker=2
#每个进程的线程数
threads=3
#记录进程ID文件
pidfile=/data/Project/python/django_project/script/uwsgi.pid
#当uwsgi服务停止的时候,是否自动删除socket和pid
vacuum=true
#启用
thunder-lock
功能,当设置为true
时,uWSGI 会使用全局文件锁来处理资源竞争问题。你也可以将其设置为false
来禁用该功能thunder-lock = true
#允许多线程(需配合'threads'使用)
enable-threads = true
#请求超时时间(秒),超时自动重启进程
harakiri = 30
#
post-buffering
设置为 65536 字节(即 64KB),意味着 uWSGI 会将 POST 请求数据# 缓冲到 64KB 后再传递给应用程序,当post-buffering
设置为 0 时,uWSGI 会采用流# 式处理的方式,将客户端发送的 POST 请求数据逐块传递给应用程序,而不会进行缓冲post_buffering = 4096
# 日志配置
daemonize = /data/Project/python/django_project/script/uwsgi.log # 后台运行并输出日志
#logto = /var/log/uwsgi.log # 等同于 daemonize(二者选一)
#disable-logging = true # 关闭请求日志(仅记录错误)#下述配置将 URL 中以
/static
开头的请求映射到服务器文件系统中的/path/to/#static/files
目录。例如,当客户端请求http://example.com/static/#style.css
时,uWSGI 会尝试从/path/to/static/files/style.css
文件中读取#内容并返回给客户端#static-map = /static=/path/to/static/files #此处暂时不用
# 虚拟环境(如果使用)
#virtualenv = /path/to/venv # (本项目Python虚拟环境路径,未使用)
-
socket
指定与Web服务器(如Nginx)通信的地址。可以是端口(如:8000
)或Unix Socket文件(如/tmp/uwsgi.sock
)。-
使用Nginx时通常选择Unix Socket(性能更好)。
-
直接对外提供HTTP服务时用
http
代替socket
。
-
-
module
指定WSGI入口,例如Django项目的myapp.wsgi:application
。 -
virtualenv
/home
指定Python虚拟环境路径,确保uWSGI使用项目依赖。 -
processes
和threads
根据服务器CPU核心数调整进程和线程数(如processes = 2 * CPU核心数
)。 -
master
启用主进程管理子进程,提高稳定性。 -
harakiri
防止请求阻塞,超时自动终止并重启进程。 -
vacuum
退出时自动清理临时文件(避免残留Socket文件导致重启失败)。
2.4生产环境建议
-
使用 Nginx 反向代理到uWSGI的Socket。
-
用 Supervisor 或 systemd 管理uWSGI进程。
-
日志分割:使用
logrotate
或daemonize
结合日志文件路径
可以把uwsgi服务的配置文件和一些服务产生的log信息等放到一个统一目录管理。
我这里是创建一个script文件夹和Django项目同级目录。
常用命令:
uwsgi --ini uwsgi.ini通过配置文件启动wsgi服务
ps -ef | grep -i uwsgi 查看uwsgi服务是否启动?
uwsgi --stop uwsgi.pid 关闭uwsgi服务。
以上命令在创建的script文件夹下执行即可
3.安装配置Nginx
3.1安装Nginx
sudo apt install nginx
也可以用yum源管理安装nginx。
3.2Nginx配置:
server{
#监听端口
listen 8080;
#建议使用域名
server_name 10.2.6.161;
# 日志配置
access_log /data/Project/python/django_project/nginx_file/form_demo.log;
error_log /data/Project/python/django_project/nginx_file/form_demo_error.log;# 启用 Gzip 压缩功能
gzip on;
# 设置允许压缩的最小响应体大小,单位为字节,小于该值的响应不会被压缩
gzip_min_length 1000;# 设置允许压缩的 MIME 类型,只有匹配这些类型的响应才会被压缩
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
# 处理静态文件请求
# 静态文件由 Nginx 直接处理(无需经过 uWSGI)
location /static/ {
# 静态文件的实际存储路径# 必须以 `/` 结尾
# 指定静态文件的根目录。当客户端请求 /static/style.css 时,Nginx 会尝试从
# /data/Project/python/django_project/nginx_file/static/style.css
# 文件中读取内容并返回给客户端
#root /data/Project/python/django_project/nginx_file/static/;# alias 指令会将 location 匹配的部分替换为指定的路径。
# 当客户端请求 /static/style.css 时,Nginx 会直接从
# /data/Project/python/django_project/nginx_file/static/style.css
# 文件中读取内容
alias /data/Project/python/django_project/nginx_file/static/;
index index.html;
}
location / {
# 包含uWSGI参数配置
include uwsgi_params;
# 使用 Unix 套接字通信,需与 uWSGI 配置一致
uwsgi_pass unix:/data/Project/python/django_project/script/uwsgi.sock;
# 连接 uWSGI 的超时时间(默认 60s)
uwsgi_connect_timeout 70;
# 等待 uWSGI 响应的超时时间(重要!)
uwsgi_read_timeout 300s;
# 发送请求到 uWSGI 的超时时间
uwsgi_send_timeout 300s;# 保持的长连接数量,版本过低会提示错误,需升级nginx版本
uwsgi_keepalive 32;
# 连接保持时间(秒)
keepalive_timeout 65;# 设置请求头信息
# proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto $scheme;}
}
配置参数解释
全局配置部分
listen
:指定 Nginx 服务器监听的端口,可以是具体的端口号(如80
),也可以是[::]:80
同时监听 IPv4 和 IPv6。server_name
:定义服务器的名称,可以是域名(如example.com
)、IP 地址或通配符(如*.example.com
),用于匹配客户端请求的域名。
日志配置部分
access_log
:指定访问日志的存储路径,记录客户端的访问信息,如请求的 URL、请求方法、响应状态码等。error_log
:指定错误日志的存储路径,记录 Nginx 运行过程中出现的错误信息,方便排查问题。
静态文件处理部分
location /static/
:定义一个匹配以/static/
开头的 URL 请求的位置块,用于处理静态文件请求。root
:指定静态文件的实际存储路径,Nginx 会根据请求的 URL 在该路径下查找对应的文件并返回给客户端。- alias 指令会将 location 匹配的部分替换为指定的路径当客户端请求 /static/style.css 时,Nginx 会直接从/data/Project/python/django_project/nginx_file/static/style.css文件中读取内容
动态请求处理部分
include uwsgi_params
:包含 Nginx 自带的uwsgi_params
文件,该文件定义了一系列 uWSGI 相关的参数,如请求的方法、URL、头部信息等,确保请求能正确传递给 uWSGI 服务器。uwsgi_pass
:指定 uWSGI 服务器的地址和端口,Nginx 会将匹配该location
块的请求转发到指定的 uWSGI 服务器进行处理。uwsgi_read_timeout
:设置 Nginx 从 uWSGI 服务器读取响应的超时时间(单位:秒),如果在该时间内没有收到响应,Nginx 会终止连接。uwsgi_send_timeout
:设置 Nginx 向 uWSGI 服务器发送请求的超时时间(单位:秒),如果在该时间内没有发送完请求,Nginx 会终止连接。uwsgi_connect_timeout
:设置 Nginx 与 uWSGI 服务器建立连接的超时时间(单位:秒),如果在该时间内无法建立连接,Nginx 会返回错误信息。proxy_set_header
:用于设置转发请求时的请求头信息,常见的设置包括Host
(客户端请求的主机名)、X-Real-IP
(客户端的真实 IP 地址)、X-Forwarded-For
(客户端的真实 IP 地址及经过的代理服务器 IP 地址)和X-Forwarded-Proto
(客户端请求使用的协议,如http
或https
),这些信息可以帮助 uWSGI 服务器获取客户端的真实信息。
nginx在测试验证中常用的命令等:
sudo service nginx start开启nginx服务
sudo service nginx stop关闭nginx服务
sudo systemctl reload nginx动态加载nginx的配置文件,适用于nginx服务未停止而修改了配置参数
sudo systemctl status nginx 查看nginx服务运行状态,
4.验证服务
建议先启动uwsgi服务再启动nginx服务,关闭时则相反即可.
4.1验证静态网页服务:
<!DOCTYPE html>
<html>
<head><title>Welcome</title>
</head>
<body><h1>Hello, World!</h1><p>This is a static webpage served by Nginx.</p>
</body>
</html>
创建以上的index.html,文件路径:/data/Project/python/django_project/nginx_file/static。
根据nginx服务配置:
。。。
#监听端口
listen 8080;
#建议使用域名
server_name 10.2.6.161;
location /static/ {
alias /data/Project/python/django_project/nginx_file/static/;
index index.html;
}。。。
在ubuntu终端先后执行命令如下:
可以在同一个pc上的浏览器直接输入地址:http://0.0.0.0:8080/static/
4.2动态服务请求验证:
贴上具体的uwsgi.ini文件:
[uwsgi]
chdir=../form_demo
uid=root
gid=root
socket = /data/Project/python/django_project/script/uwsgi.sock
chmod-socket = 666
module = form_demo.wsgi
master = true
workers = 2
threads = 3
pidfile=./uwsgi.pid
logto = ./uwsgi.log
daemonize = ./uwsgi.log
vacuum = true
自己撰写的Nginx confgi文件,路径:/etc/nginx/conf.d/form_demo.conf。最终的配置结果可以通过命令: sudo nginx -T查看有效的配置.
server{
#监听端口
listen 8080;
#建议使用域名
server_name 10.2.6.161;
# 日志配置
access_log /data/Project/python/django_project/nginx_file/form_demo.log;
error_log /data/Project/python/django_project/nginx_file/form_demo_error.log;
# 启用 Gzip 压缩功能
#gzip on;
# 设置允许压缩的最小响应体大小,单位为字节,小于该值的响应不会被压缩
#gzip_min_length 1000;# 设置允许压缩的 MIME 类型,只有匹配这些类型的响应才会被压缩
#gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
# 处理静态文件请求
# 静态文件由 Nginx 直接处理(无需经过 uWSGI)
location /static/ {
# 静态文件的实际存储路径# 必须以 `/` 结尾
alias /data/Project/python/django_project/nginx_file/static/;
index index.html;
}
location / {
# 包含uWSGI参数配置
include uwsgi_params;
# 连接 uWSGI 的超时时间(默认 60s)
uwsgi_connect_timeout 70;
uwsgi_pass unix:/data/Project/python/django_project/script/uwsgi.sock;
# 等待 uWSGI 响应的超时时间(重要!)
#uwsgi_read_timeout 300s;
# 发送请求到 uWSGI 的超时时间
#uwsgi_send_timeout 300s;# 保持的长连接数量
#uwsgi_keepalive 32;
# 连接保持时间(秒)
#keepalive_timeout 65;# 设置请求头信息
# proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto $scheme;}
}
nginx配置包含哪些路径配置可以查看:/etc/nginx/nginx.conf,通常自己写的配置文件可以放在目录:/etc/nginx/conf.d。
操作命令:
Django项目名字form_demo,目录结果如下:
form_demo->urls.py 代码如下:
from django.contrib import admin
from django.urls import path,includeurlpatterns = [path('admin/', admin.site.urls),# 新增path('front/',include('front.urls')),
]
front->urls.py代码如下:
from django.urls import path
from . import viewsurlpatterns = [path('', views.index,name = 'index_view'),path('register', views.register_view,name = 'register_view'),path('article', views.article_view,name = 'article_view'),
]
front->views.py代码如下:
from django.shortcuts import render,HttpResponsefrom .forms import MessageBoardForm,RegisterForm,ArticleForm# Create your views here.#请求的method
#1 Get 请求
#2 Post 请求def index(request):#如果是get请求就返回一个模板:if request.method == 'GET':form = MessageBoardForm()return render(request,'index.html',context={'form':form})elif request.method == 'POST':# 对用post提交的数据进行数据验证form = MessageBoardForm(request.POST)if form.is_valid():#验证通过:content = form.cleaned_data.get('content')title = form.cleaned_data.get('title')email = form.cleaned_data.get('email')return HttpResponse(f'{content},{title},{email}')else:#表单验证失败:print(form.errors)return HttpResponse('表单验证失败')def register_view(request):if request.method == 'GET':return render(request,'register.html')elif request.method == 'POST':form = RegisterForm(request.POST)if form.is_valid():phone = form.cleaned_data.get('phone')print('phone is %s'%phone)return HttpResponse(f'{phone}')else:print(form.errors)return HttpResponse('表单验证失败')def article_view(request):if request.method == 'GET':return render(request,'article.html')elif request.method == 'POST':form = ArticleForm(request.POST)if form.is_valid():title = form.cleaned_data.get('title')content = form.cleaned_data.get('content')return HttpResponse(f'{title},{content}')else:print(form.errors)return HttpResponse('表单验证失败')
front->form.py代码如下:
from django import forms
from django.core.validators import RegexValidator
from .models import Article
#留言板的表单class MessageBoardForm(forms.Form):title = forms.CharField(max_length=100,min_length=2,label='标题',error_messages={'required':'标题不能为空','min_length':'标题不能小于2个字符','max_length':'标题不能大于100个字符'})content = forms.CharField(widget=forms.Textarea,label='内容')email = forms.EmailField(label='邮箱')class RegisterForm(forms.Form):phone = forms.CharField(validators=[RegexValidator(r'^1[3-8]\d{9}$',message='电话手机号格式不正确')])def clean_phone(self):phone = self.cleaned_data.get('phone')return phoneclass ArticleForm(forms.ModelForm):class Meta:model = Articlefields = '__all__'#fields = ['title','content']# 测试fields = '__all__' 时 category字段 blank=False,提示信息。error_messages = {'category':{'required':'分类字段不能为空'}}
form->settings.py配置如下:
"""
Django settings for form_demo project.Generated by 'django-admin startproject' using Django 4.2.18.For more information on this file, see
https://docs.djangoproject.com/en/4.2/topics/settings/For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/
"""from pathlib import Path# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-6@rc#x8(#!x5*r#ol6cj$u()^7d28*0^k#qj*%_*ojbc303t8b'# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = TrueALLOWED_HOSTS = []# Application definitionINSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','front',
]MIDDLEWARE = ['django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',
]ROOT_URLCONF = 'form_demo.urls'TEMPLATES = [{'BACKEND': 'django.template.backends.django.DjangoTemplates','DIRS': [BASE_DIR / 'templates'],'APP_DIRS': True,'OPTIONS': {'context_processors': ['django.template.context_processors.debug','django.template.context_processors.request','django.contrib.auth.context_processors.auth','django.contrib.messages.context_processors.messages',],},},
]WSGI_APPLICATION = 'form_demo.wsgi.application'# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databasesDATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3','NAME': BASE_DIR / 'db.sqlite3',}
}# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validatorsAUTH_PASSWORD_VALIDATORS = [{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',},{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',},{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',},{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',},
]# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/LANGUAGE_CODE = 'en-us'TIME_ZONE = 'UTC'USE_I18N = TrueUSE_TZ = True# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/STATIC_URL = 'static/'# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-fieldDEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
新建的templates文件夹下是存放的模板html:
index.html文件如下:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Front页面</title>
</head>
<body><h1>留言板</h1><form action="" method="post">{{ form }}<input type="submit" value="提交"></form></body>
</html>
article.html如下:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>article</title>
</head>
<body><form action="" method="post"><div><input type="text" name="title" placeholder="请输入标题"></div><div><textarea name="content" id="" cols="30" rows="10" placeholder="请输入内容"></textarea></div><div><input type="submit" value="提交"></div></form>
</body>
</html>
article.html如下:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>注册</title>
</head>
<body><form action="" method="post"><input type="text" name="phone"><input type="submit" value="提交"></form>
</body>
</html>
在浏览器验证结果(http://localhost:8080/front/),不是专业的html人员,凑合看,勿喷!
验证(http://localhost:8080/front/article)
以上是操作nginx,uwsgi,django的基本操作,不够全面与细致,仅供参考!