第6章:动态内容处理

6.1 FastCGI配置

FastCGI(Fast Common Gateway Interface)是一种用于在Web服务器和应用服务器之间通信的协议,比传统的CGI更加高效。

6.1.1 PHP-FPM集成

PHP-FPM(PHP FastCGI Process Manager)是PHP的FastCGI实现,用于处理PHP脚本请求。

安装PHP-FPM

# Ubuntu/Debian
sudo apt-get update
sudo apt-get install -y php-fpm php-mysql

# CentOS/RHEL
sudo yum install -y php-fpm php-mysqlnd

配置示例

server {
    listen 80;
    server_name example.com;
    
    root /var/www/html;
    index index.php index.html index.htm;
    
    location / {
        try_files $uri $uri/ =404;
    }
    
    # PHP-FPM配置
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; # Ubuntu/Debian
        # fastcgi_pass 127.0.0.1:9000; # CentOS/RHEL
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

指令说明

  • fastcgi_pass:指定PHP-FPM的监听地址(可以是Unix套接字或TCP地址)
  • fastcgi_param:设置FastCGI参数
  • include fastcgi_params:包含默认的FastCGI参数配置

验证配置

  1. 创建测试PHP文件:

sudo nano /var/www/html/info.php

   添加:
   ```php
<?php phpinfo(); ?>
  1. 访问测试文件:

curl http://example.com/info.php

   或通过浏览器访问:http://example.com/info.php

### 6.1.2 Python应用(uWSGI/Gunicorn)

Nginx可以作为Python Web应用(如Django、Flask)的反向代理,配合uWSGI或Gunicorn等WSGI服务器使用。

#### 6.1.2.1 使用uWSGI

**安装uWSGI**:
```bash
pip install uwsgi

Flask应用示例

# app.py
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello():
    return "Hello from Flask!"

if __name__ == '__main__':
    app.run()

启动uWSGI

uwsgi --socket 127.0.0.1:5000 --wsgi-file app.py --callable app

Nginx配置

server {
    listen 80;
    server_name example.com;
    
    location / {
        include uwsgi_params;
        uwsgi_pass 127.0.0.1:5000;
    }
}

6.1.2.2 使用Gunicorn

安装Gunicorn

pip install gunicorn

启动Gunicorn

gunicorn -w 4 -b 127.0.0.1:5000 app:app

Nginx配置

server {
    listen 80;
    server_name example.com;
    
    location / {
        proxy_pass http://127.0.0.1:5000;
        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;
    }
}

6.2 WebSocket代理

WebSocket是一种全双工通信协议,允许服务器主动向客户端发送消息。Nginx可以作为WebSocket代理,将WebSocket连接转发到后端服务器。

6.2.1 WebSocket协议支持

配置示例

upstream websocket {
    server 127.0.0.1:3000;
}

server {
    listen 80;
    server_name example.com;
    
    location /ws {
        # 允许WebSocket连接升级
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        
        # 转发到后端服务器
        proxy_pass http://websocket;
        
        # 设置较长的超时时间
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }
}

指令说明

  • proxy_http_version 1.1:使用HTTP/1.1协议
  • proxy_set_header Upgrade $http_upgrade:传递Upgrade头
  • proxy_set_header Connection &quot;upgrade&quot;:传递Connection头,设置为upgrade
  • proxy_read_timeoutproxy_send_timeout:设置较长的超时时间,防止WebSocket连接被意外关闭

6.2.2 实时应用配置示例

创建WebSocket服务器示例(Node.js)

// server.js
const http = require('http');
const WebSocket = require('ws');

const server = http.createServer((req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('WebSocket Server\n');
});

const wss = new WebSocket.Server({ server });

wss.on('connection', (ws) => {
    console.log('Client connected');
    
    // 发送欢迎消息
    ws.send('Welcome to WebSocket Server!');
    
    // 接收客户端消息
    ws.on('message', (message) => {
        console.log(`Received: ${message}`);
        // 发送回声
        ws.send(`Echo: ${message}`);
    });
    
    // 客户端断开连接
    ws.on('close', () => {
        console.log('Client disconnected');
    });
});

server.listen(3000, () => {
    console.log('Server listening on port 3000');
});

安装依赖并启动服务器

npm install ws
node server.js

创建WebSocket客户端示例

<!DOCTYPE html>
<html>
<head>
    <title>WebSocket Client</title>
</head>
<body>
    <h1>WebSocket Client</h1>
    <div>
        <input type="text" id="message" placeholder="Enter message">
        <button onclick="sendMessage()">Send</button>
    </div>
    <div id="messages"></div>
    
    <script>
        const socket = new WebSocket('ws://example.com/ws');
        const messagesDiv = document.getElementById('messages');
        const messageInput = document.getElementById('message');
        
        socket.onopen = () => {
            addMessage('Connected to server');
        };
        
        socket.onmessage = (event) => {
            addMessage(`Server: ${event.data}`);
        };
        
        socket.onclose = () => {
            addMessage('Disconnected from server');
        };
        
        function sendMessage() {
            const message = messageInput.value;
            if (message) {
                socket.send(message);
                addMessage(`Client: ${message}`);
                messageInput.value = '';
            }
        }
        
        function addMessage(message) {
            const div = document.createElement('div');
            div.textContent = message;
            messagesDiv.appendChild(div);
        }
    </script>
</body>
</html>

验证配置

  • 将客户端HTML文件部署到Nginx的网站目录
  • 通过浏览器访问客户端页面
  • 输入消息并发送,观察是否能正常接收服务器的回声

6.3 HTTP/2与HTTP/3

6.3.1 HTTP/2配置与优化

HTTP/2是HTTP协议的重大升级,提供了多路复用、服务器推送、头部压缩等功能,提高了Web性能。

配置示例

server {
    listen 443 ssl http2;
    server_name example.com;
    
    # SSL证书配置
    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;
    
    # HTTP/2优化配置
    http2_max_field_size 4k;
    http2_max_header_size 16k;
    http2_max_concurrent_streams 128;
    
    # ... 其他配置 ...
}

指令说明

  • listen 443 ssl http2:在443端口启用SSL和HTTP/2
  • http2_max_field_size:设置HTTP/2头部字段的最大大小
  • http2_max_header_size:设置HTTP/2头部的最大大小
  • http2_max_concurrent_streams:设置每个连接的最大并发流数量

验证HTTP/2是否启用

# 使用curl验证
curl -I --http2 -k https://example.com

# 或使用浏览器开发者工具
# 在Chrome中,打开开发者工具 → Network → 勾选Protocol列,查看请求的协议

预期输出(包含HTTP/2):

HTTP/2 200

6.3.2 HTTP/3(QUIC)前瞻

HTTP/3是基于QUIC协议的HTTP版本,提供了更快的连接建立、更好的多路复用和连接迁移等功能。

Nginx HTTP/3配置示例

server {
    listen 443 ssl http2;
    listen 443 quic reuseport;
    server_name example.com;
    
    # SSL证书配置
    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;
    
    # HTTP/3配置
    add_header Alt-Svc 'h3=":443"; ma=86400';
    
    # ... 其他配置 ...
}

注意

  • HTTP/3支持需要Nginx 1.19.0或更高版本,并且需要使用--with-http_v3_module编译
  • QUIC协议需要使用UDP端口,默认与HTTPS端口相同
  • Alt-Svc头用于告诉客户端服务器支持HTTP/3

验证HTTP/3是否启用

# 使用支持HTTP/3的curl版本
curl -I --http3 -k https://example.com

6.4 实战项目:部署Django应用

在这个实战项目中,我们将使用Nginx和Gunicorn部署一个Django应用。

6.4.1 项目准备

1. 安装依赖

# 安装Python和pip
sudo apt-get update
sudo apt-get install -y python3 python3-pip python3-venv

# 安装Nginx
sudo apt-get install -y nginx

2. 创建Django应用

# 创建项目目录
mkdir -p ~/django-project
cd ~/django-project

# 创建虚拟环境
python3 -m venv venv

# 激活虚拟环境
source venv/bin/activate

# 安装Django和Gunicorn
pip install django gunicorn

# 创建Django项目
django-admin startproject mysite
cd mysite

# 迁移数据库
python manage.py migrate

# 创建超级用户(可选)
python manage.py createsuperuser

# 测试运行
python manage.py runserver 0.0.0.0:8000

3. 测试Gunicorn

# 激活虚拟环境
source ~/django-project/venv/bin/activate
cd ~/django-project/mysite

# 测试Gunicorn是否能正常运行Django应用
gunicorn --bind 0.0.0.0:8000 mysite.wsgi

6.4.2 配置Gunicorn系统服务

1. 创建Gunicorn服务文件

sudo nano /etc/systemd/system/gunicorn.service

2. 添加以下内容

[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/django-project/mysite
ExecStart=/home/ubuntu/django-project/venv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/ubuntu/django-project/mysite/mysite.sock mysite.wsgi:application

[Install]
WantedBy=multi-user.target

3. 启动Gunicorn服务

sudo systemctl start gunicorn
sudo systemctl enable gunicorn
sudo systemctl status gunicorn

6.4.3 配置Nginx

1. 创建Nginx配置文件

sudo nano /etc/nginx/conf.d/django.conf

2. 添加以下内容

server {
    listen 80;
    server_name example.com;
    
    location = /favicon.ico {
        access_log off;
        log_not_found off;
    }
    
    # 静态文件配置
    location /static/ {
        root /home/ubuntu/django-project/mysite;
    }
    
    # 媒体文件配置
    location /media/ {
        root /home/ubuntu/django-project/mysite;
    }
    
    # 动态内容配置
    location / {
        include proxy_params;
        proxy_pass http://unix:/home/ubuntu/django-project/mysite/mysite.sock;
    }
}

3. 配置Django静态文件

# 编辑Django设置文件
nano ~/django-project/mysite/mysite/settings.py

添加或修改以下内容:

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')

4. 收集静态文件

# 激活虚拟环境
source ~/django-project/venv/bin/activate
cd ~/django-project/mysite

# 收集静态文件
python manage.py collectstatic

5. 验证Nginx配置

sudo nginx -t
sudo systemctl reload nginx

6.4.4 测试部署

1. 访问Django应用

通过浏览器访问:http://example.com

2. 访问管理界面

http://example.com/admin

3. 查看日志

# 查看Gunicorn日志
sudo journalctl -u gunicorn

# 查看Nginx访问日志
sudo tail -f /var/log/nginx/access.log

# 查看Nginx错误日志
sudo tail -f /var/log/nginx/error.log

6.4.5 常见问题与解决方案

问题1:502 Bad Gateway错误

解决方案

  1. 检查Gunicorn服务是否运行:

    sudo systemctl status gunicorn
  2. 检查socket文件权限:

    ls -la /home/ubuntu/django-project/mysite/mysite.sock

    确保文件归www-data组所有

  3. 检查Nginx配置中的socket路径是否正确

问题2:静态文件无法加载

解决方案

  1. 确保已运行collectstatic命令
  2. 检查Nginx配置中的静态文件路径是否正确
  3. 检查静态文件权限:
    sudo chown -R www-data:www-data /home/ubuntu/django-project/mysite/static

问题3:Django admin样式丢失

解决方案

  1. 确保已运行collectstatic命令
  2. 检查Nginx配置中的location /static/是否正确配置
  3. 检查STATIC_ROOT设置是否正确

章节总结

在本章中,我们学习了:

  1. FastCGI配置

    • PHP-FPM集成配置
    • Python应用(uWSGI/Gunicorn)配置
  2. WebSocket代理

    • WebSocket协议支持配置
    • 实时应用配置示例
  3. HTTP/2与HTTP/3

    • HTTP/2配置与优化
    • HTTP/3(QUIC)前瞻
  4. 实战项目

    • 部署Django应用
    • 配置Gunicorn系统服务
    • 配置Nginx反向代理
    • 解决常见问题

实践练习

  1. 配置Nginx与PHP-FPM集成
  2. 部署一个Flask应用,使用Gunicorn和Nginx
  3. 创建一个WebSocket服务器和客户端,使用Nginx代理
  4. 为网站启用HTTP/2
  5. 部署一个Django应用,包括静态文件配置

延伸阅读


下一章第7章:缓存策略

« 上一篇 安全与性能 下一篇 » 缓存策略