Deploy.php Webhook接口
PHP Webhook控制器,处理Gitee推送事件并触发部署脚本
<?php
namespace app\controller\common;
use app\BaseController;
class Deploy extends BaseController
{
public function index()
{
// 密码验证
$correct_password = '123456';
$request_password = '';
$dir = 'zdbs.localbird.cn';
// 获取密码
if (isset($_SERVER['HTTP_X_GITEE_TOKEN'])) {
$request_password = $_SERVER['HTTP_X_GITEE_TOKEN'];
}
// 验证密码
if ($request_password !== $correct_password) {
return json(['code' => 401, 'msg' => '密码验证失败']);
}
// 检查是否是ping测试
if (isset($_SERVER['HTTP_X_GITEE_PING']) && $_SERVER['HTTP_X_GITEE_PING'] === 'true') {
return json([
'code' => 200,
'msg' => 'Ping测试成功',
'data' => ['time' => date('Y-m-d H:i:s')]
]);
}
// 获取仓库信息
$input = file_get_contents('php://input');
$data = json_decode($input, true);
$repo_name = 'webhook触发';
if (!empty($data) && isset($data['repository']['name'])) {
$repo_name = $data['repository']['name'];
}
// 执行部署脚本
$script_path = '/www/wwwroot/' . $dir . '/scripts/build-temp.sh';
$log_file = '/www/wwwroot/' . $dir . '/runtime/log/deploy_' . date('Ymd_His') . '.log';
// 创建日志目录
$log_dir = '/www/wwwroot/' . $dir . '/runtime/log';
if (!is_dir($log_dir)) {
mkdir($log_dir, 0755, true);
}
// 检查脚本是否存在
if (!file_exists($script_path)) {
return json([
'code' => 500,
'msg' => '部署脚本不存在',
'data' => ['script_path' => $script_path]
]);
}
// 尝试多种命令执行方式
try {
$command = "cd /www/wwwroot/" . $dir . " && bash " . escapeshellarg($script_path) . " > " . escapeshellarg($log_file) . " 2>&1 &";
// 使用shell_exec执行命令
$result = shell_exec($command);
return json([
'code' => 200,
'msg' => '部署任务已启动',
'data' => [
'time' => date('Y-m-d H:i:s'),
'repository' => $repo_name,
'log_file' => basename($log_file),
'command' => $command,
'method' => 'shell_exec',
'result' => $result,
'status' => '部署脚本正在后台执行,请稍后查看日志文件'
]
]);
} catch (\Exception $e) {
return json([
'code' => 500,
'msg' => '执行部署失败: ' . $e->getMessage(),
'data' => [
'command' => $command ?? 'undefined'
]
]);
}
}
}build-temp.sh 部署脚本
Bash自动化部署脚本,适用于宝塔服务器环境
#!/bin/bash
# Vue项目自动部署脚本 - 适用于宝塔服务器
# 修改下面的git地址为你的仓库地址
GIT_URL="https://gitee.com/wuhuanmayun/automated-deployment-testing.git"
# 获取脚本所在目录的上级目录(网站根目录)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
WEB_ROOT="$(dirname "$SCRIPT_DIR")"
echo "$(date '+%Y-%m-%d %H:%M:%S') - 开始自动部署..."
# 进入网站根目录
cd "$WEB_ROOT"
# 1. 如果buildTemp文件夹不存在就克隆,存在就更新
if [ ! -d "buildTemp" ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - 克隆项目..."
git clone "$GIT_URL" buildTemp
if [ $? -ne 0 ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - 克隆失败!"
exit 1
fi
else
echo "$(date '+%Y-%m-%d %H:%M:%S') - 更新代码..."
cd buildTemp
git reset --hard HEAD
git clean -fd
git fetch --all
# 设置pull策略为merge,避免警告
git config pull.rebase false
git pull origin main || git pull origin master
if [ $? -ne 0 ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - 代码更新失败!"
exit 1
fi
cd "$WEB_ROOT"
fi
# 2. 进入项目文件夹
cd buildTemp
# 3. 安装依赖
echo "$(date '+%Y-%m-%d %H:%M:%S') - 安装依赖..."
# 清理npm缓存并重新安装
npm cache clean --force
npm install
if [ $? -ne 0 ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - 依赖安装失败!"
exit 1
fi
# 检查vite是否正确安装
echo "$(date '+%Y-%m-%d %H:%M:%S') - 检查vite安装状态..."
if [ -f "node_modules/.bin/vite" ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - vite已安装在 node_modules/.bin/vite"
else
echo "$(date '+%Y-%m-%d %H:%M:%S') - vite未找到,尝试安装..."
npm install vite --save-dev
fi
# 4. 打包项目
echo "$(date '+%Y-%m-%d %H:%M:%S') - 打包项目..."
# 方法1: 直接调用本地vite
if [ -f "node_modules/.bin/vite" ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - 使用本地vite构建..."
./node_modules/.bin/vite build
if [ $? -eq 0 ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - 本地vite构建成功!"
else
echo "$(date '+%Y-%m-%d %H:%M:%S') - 本地vite构建失败!"
fi
fi
# 方法2: 如果上面失败,尝试npx
if [ ! -d "dist" ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - 尝试使用npx vite build..."
npx vite build
if [ $? -eq 0 ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - npx构建成功!"
else
echo "$(date '+%Y-%m-%d %H:%M:%S') - npx构建失败!"
fi
fi
# 方法3: 如果还是失败,尝试npm run build
if [ ! -d "dist" ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - 尝试使用npm run build..."
npm run build
if [ $? -eq 0 ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - npm run build成功!"
else
echo "$(date '+%Y-%m-%d %H:%M:%S') - npm run build失败!"
fi
fi
# 检查是否成功生成dist目录
if [ ! -d "dist" ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - 所有打包方式都失败!未生成dist目录"
exit 1
else
echo "$(date '+%Y-%m-%d %H:%M:%S') - 打包成功,dist目录已生成"
fi
# 5. 复制文件到public/user目录
echo "$(date '+%Y-%m-%d %H:%M:%S') - 复制文件..."
cd "$WEB_ROOT"
# 确保public/user目录存在
mkdir -p public/user
# 清空目标目录但保留重要文件
cd public/user
find . -maxdepth 1 ! -name '.htaccess' ! -name '.user.ini' ! -name '.' -exec rm -rf {} + 2>/dev/null || true
# 复制新文件
cd "$WEB_ROOT"
if [ -d "buildTemp/dist" ] && [ "$(ls -A buildTemp/dist)" ]; then
cp -r buildTemp/dist/* public/user/
echo "$(date '+%Y-%m-%d %H:%M:%S') - 文件复制成功!"
else
echo "$(date '+%Y-%m-%d %H:%M:%S') - dist目录为空或不存在!"
exit 1
fi
# 6. 设置权限(宝塔环境)
chown -R www:www public/user
chmod -R 755 public/user
echo "$(date '+%Y-%m-%d %H:%M:%S') - 部署完成!"Nginx配置文件
完整的Nginx配置示例:缓存、压缩、限流、负载均衡、反向代理
events {
worker_connections 1024;
}
http {
# 配置缓存区域
proxy_cache_path /tmp/nginx_cache
levels=1:2
keys_zone=my_cache:10m
max_size=100m
inactive=10m;
# 性能优化配置
sendfile on; # 启用高效文件传输
tcp_nopush on; # 优化 TCP 数据包发送
tcp_nodelay on; # 禁用 Nagle 算法,减少延迟
keepalive_timeout 65; # 保持连接超时时间
types_hash_max_size 2048; # 类型哈希表大小
# Gzip 压缩(减少响应客户端传输大小)
gzip on; # 启用 Gzip 压缩
gzip_vary on; # 根据 Accept-Encoding 头决定是否压缩
gzip_proxied any; # 对所有代理请求启用压缩
gzip_comp_level 6; # 压缩级别(1-9,6 是平衡点)
gzip_types # 压缩的文件类型
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/rss+xml
image/svg+xml;
gzip_min_length 1000; # 只压缩大于 1KB 的文件
gzip_disable "msie6"; # 禁用 IE6 的压缩(IE6 有 bug)
# 文件上传大小限制
client_max_body_size 100M; # 最大请求体大小
client_body_buffer_size 128k; # 请求体缓冲区大小
client_body_timeout 60s; # 请求体超时时间
# 限流配置(防止恶意请求)
# 定义限流区域:zone=名称:大小 rate=速率
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s; # API 限流:每秒 10 个请求
limit_req_zone $binary_remote_addr zone=login_limit:10m rate=1r/s; # 登录限流:每秒 1 个请求
# 连接数限制
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
# 负载均衡配置
# 轮询策略(默认)
upstream backend_round_robin {
server 127.0.0.1:3000;
server 127.0.0.1:3001;
server 127.0.0.1:3002;
}
# 权重策略(weight 越大,分配请求越多)
upstream backend_weighted {
server 127.0.0.1:3000 weight=3; # 权重 3
server 127.0.0.1:3001 weight=2; # 权重 2
server 127.0.0.1:3002 weight=1; # 权重 1
}
# 最少连接数策略
upstream backend_least_conn {
least_conn;
server 127.0.0.1:3000;
server 127.0.0.1:3001;
server 127.0.0.1:3002;
}
# IP 哈希策略(会话保持,同一 IP 总是访问同一服务器)
upstream backend_ip_hash {
ip_hash;
server 127.0.0.1:3000;
server 127.0.0.1:3001;
server 127.0.0.1:3002;
}
# 服务器配置一
server {
listen 8083;
server_name localhost;
location /login {
# 应用限流
limit_req zone=login_limit burst=2 nodelay;
proxy_pass http://backend_ip_hash;
}
location /api/upload {
# 文件上传接口,使用最少连接策略
# 注意:这个 location 会优先匹配,不会走到 /api
proxy_pass http://backend_least_conn;
# 可以针对上传接口单独设置限流(可选)
limit_req zone=api_limit burst=5 nodelay;
}
location /api {
# 应用限流
limit_req zone=api_limit burst=20 nodelay;
# 启动缓存
proxy_cache my_cache;
# 缓存规则
proxy_cache_valid 200 302 5m;
proxy_cache_valid 404 1m;
proxy_cache_valid any 0;
# 缓存键(使用原始 URI,包含 /api 前缀)
# 注意:如果 rewrite 在 proxy_cache_key 之后,缓存键使用原始 URI
# 如果 rewrite 在 proxy_cache_key 之前,缓存键使用重写后的 URI
proxy_cache_key "$scheme$request_method$host$request_uri";
# 缓存状态头
add_header X-Cache-Status $upstream_cache_status;
# 其他代理设置
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 去掉 /api 前缀,然后代理到后端服务器
rewrite ^/api/(.*)$ /$1 break;
# 反向代理
proxy_pass http://backend_round_robin;
}
# 默认放在最后
location / {
root /Users/wuhuan/Desktop/前端资料/工作笔记/nginx_study;
index test.html;
}
}
# 服务器配置二
server {
listen 8084;
server_name localhost;
location / {
root /Users/wuhuan/Desktop/前端资料/工作笔记/nginx_study;
index index.html;
}
}
}