文章目录
- 前:vue 后:django 部署:supervisor+nginx 流程及部分问题简记
- 一、服务器环境准备
- 二、后端 django部署
- 三、nginx处配置
- ps:补充一个问题:如有涉及文件上传,nginx处还需配置,之前在本地测无问题,部署后上传失败,简记流程
前:vue 后:django 部署:supervisor+nginx 流程及部分问题简记
一、服务器环境准备
安装必要的软件:
sudo apt update && sudo apt install -y python3-pip python3-venv supervisor
如果是 CentOS:
sudo yum install -y python3-pip python3-venv supervisor
检查是否安装成功:
python3 --version
pip3 --version
supervisord --version
二、后端 django部署
克隆项目至服务器本地:
cd /data
git clone https://github.com/your-repo/django-project.git
cd django-project
创建 Python 虚拟环境:
python3 -m venv venv
source venv/bin/activate# 安装依赖
pip install --upgrade pip
pip install -r requirements.txt
安装gunicorn:
pip install gunicorn# 测试运行 Gunicorn
gunicorn --workers 3 --bind 0.0.0.0:8000 django-project.wsgi:application
配置Supervisor:
在项目文件夹下创建 supervisord.d 文件夹,下创建django-project-wsgi.ini
[program:django-project-wsgi]
directory = /data/gitcode/django-project
command = /data/gitcode/django-project/venv/bin/gunicorn -w4 -b 0.0.0.0:8000 django-project.wsgi --timeout 1800 --keep-alive 30
numprocs = 1
autostart = true
autorestart = true
redirect_stderr = true
stdout_logfile = /data/gitcode/logs/django-project.log
stderr_logfile = /data/gitcode/logs/django-project_err.log
可以在该项目文件夹下创建启动的shell脚本:
#!/bin/bash
sudo supervisorctl restart django-project-wsgi
三、nginx处配置
server {listen 8082;server_name 【服务器IP】;#charset koi8-r;#access_log logs/host.access.log main;location / {root html/dist; # 前端vue打包的dist放置位置index index.html index.htm;try_files $uri $uri/ /index.html;}location /api/ {proxy_pass http://【服务器IP】:8000;}location @router {rewrite ^.*$ /index.html last;}error_page 500 502 503 504 /50x.html;location = /50x.html {root html;}}
可写一个shell脚本重启:
sudo systemctl restart nginx
sudo /usr/local/nginx/sbin/nginx -s reload
sudo chmod -R 777 /usr/local/nginx/html/dist
ps:补充一个问题:如有涉及文件上传,nginx处还需配置,之前在本地测无问题,部署后上传失败,简记流程
vue:
<template><Card style="width: 100%; height: 115%"><div><Upload:before-upload="beforeUpload":on-success="handleSuccess":on-error="handleError"accept=".csv"><Button type="primary">上传 CSV 文件</Button></Upload><div style="height: 10px"></div><Alert show-icon>已上传文件: <span>{{ uploadedFileName }}</span></Alert><div v-if="duplicates.length > 0"><Alert show-icon type="warning">重复的 MAC 地址 <b>({{ duplicates.length }})</b>:<Scroll :height="400"><ul><li v-for="mac in duplicates" :key="mac">{{ mac }}</li></ul></Scroll></Alert><Button type="success" @click="downloadDuplicates">下载重复的 MAC 地址</Button></div><div v-else><Alert show-icon type="success">没有重复的 MAC 地址</Alert></div></div></Card>
</template><script>
import { Upload, Button, Alert, Card, Scroll } from 'iview';
import axios from 'axios';export default {components: {Upload,Button,Alert,Card,Scroll},data() {return {uploadedFileName: '',duplicates: []};},methods: {beforeUpload(file) {this.uploadedFileName = file.name;const formData = new FormData();formData.append('file', file);axios.post('/api/upload-csv/', formData, {headers: {'Content-Type': 'multipart/form-data'}}).then(response => {this.handleSuccess(response);}).catch(error => {this.handleError(error);});return false; // Prevent default upload behavior},handleSuccess(response) {this.$Message.success('文件上传成功');this.duplicates = response.data.duplicates;},handleError(error) {this.$Message.error('文件上传失败');},downloadDuplicates() {const blob = new Blob([this.duplicates.join(', ')], { type: 'text/plain' });const url = window.URL.createObjectURL(blob);const a = document.createElement('a');a.href = url;a.download = 'duplicates.txt';document.body.appendChild(a);a.click();document.body.removeChild(a);window.URL.revokeObjectURL(url);}}
};
</script><style scoped>
.custom-bread-crumb {margin-bottom: 20px;
}
</style>
export const uploadCsvFile = (file, token) => {const formData = new FormData();formData.append('file', file);return axios.request({url: '/api/upload-csv/',method: 'post',headers: {'Authorization': `Token ${token}`,'Content-Type': 'multipart/form-data'},data: formData})
}
django views.py
UPLOAD_FOLDER = 'uploads'
if not os.path.exists(UPLOAD_FOLDER):os.makedirs(UPLOAD_FOLDER)class HandleNacMultipulRecords(APIView):def post(self, request):if 'file' not in request.FILES:return Response({'error': 'No file part'}, status=status.HTTP_400_BAD_REQUEST)file = request.FILES['file']if file.name == '':return Response({'error': 'No selected file'}, status=status.HTTP_400_BAD_REQUEST)if file.name.endswith('.csv'):file_path = os.path.join(UPLOAD_FOLDER, file.name)with open(file_path, 'wb+') as destination:for chunk in file.chunks():destination.write(chunk)# 解析 CSV 文件并提取 MAC Address 列mac_addresses = []with open(file_path, newline='', encoding='utf-8') as csvfile:csv_reader = csv.DictReader(csvfile)for row in csv_reader:mac_addresses.append(row['MAC Address'])# 删除上传的文件# os.remove(file_path)# 验证 MAC 地址格式valid_mac_addresses = [mac for mac in mac_addresses ifre.match(r'^([0-9A-Fa-f]{2}){5}[0-9A-Fa-f]{2}$', mac)]mac_counter = Counter(valid_mac_addresses)duplicates = [mac for mac, count in mac_counter.items() if count > 1]logger.info(duplicates)return Response({'message': 'File uploaded successfully','valid_mac_addresses': valid_mac_addresses,'duplicates': duplicates}, status=status.HTTP_200_OK)return Response({'error': 'Invalid file type'}, status=status.HTTP_400_BAD_REQUEST)
http {include mime.types;default_type application/octet-stream;sendfile on;keepalive_timeout 65;client_max_body_size 100M; # 注意:这里需设置,否则会上传失败!#gzip on;include /usr/local/nginx/conf/conf.d/*.conf;...