乐闻世界logo
搜索文章和话题

服务端面试题手册

Nginx 如何配置 HTTPS 和 SSL 证书?

Nginx 如何配置 HTTPS 和 SSL 证书?Nginx 配置 HTTPS 需要使用 SSL 模块,通过配置 SSL 证书来启用加密通信。HTTPS 可以保护数据传输的安全性,防止数据被窃听或篡改。基本配置示例:server { listen 443 ssl; server_name example.com; ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; location / { root /var/www/html; index index.html; }}SSL 证书配置参数:server { listen 443 ssl http2; server_name example.com; # 证书文件路径 ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; # SSL 协议版本 ssl_protocols TLSv1.2 TLSv1.3; # 加密套件 ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; # SSL 会话缓存 ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # OCSP Stapling ssl_stapling on; ssl_stapling_verify on; ssl_trusted_certificate /etc/nginx/ssl/chain.crt; # HSTS add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;}HTTP 自动跳转 HTTPS:server { listen 80; server_name example.com; return 301 https://$server_name$request_uri;}server { listen 443 ssl; server_name example.com; ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; location / { root /var/www/html; }}SSL 证书类型:自签名证书:用于测试环境,不被浏览器信任免费证书:如 Let's Encrypt,有效期 90 天,可自动续期商业证书:由 CA 机构颁发,有效期通常为 1 年Let's Encrypt 证书申请:使用 Certbot 工具申请免费证书:# 安装 Certbotsudo apt-get install certbot python3-certbot-nginx# 申请证书并自动配置 Nginxsudo certbot --nginx -d example.com -d www.example.com# 只申请证书,不自动配置sudo certbot certonly --nginx -d example.com证书续期:# 手动续期sudo certbot renew# 自动续期(添加到 crontab)0 0,12 * * * certbot renew --quiet安全配置建议:使用 TLS 1.2 或更高版本禁用弱加密套件启用 HSTS 防止降级攻击配置 OCSP Stapling 提高性能定期更新证书使用强密钥(至少 2048 位)启用 HTTP/2 提升性能性能优化:# SSL 会话缓存ssl_session_cache shared:SSL:50m;ssl_session_timeout 1d;# 启用 HTTP/2listen 443 ssl http2;# SSL 缓冲区大小ssl_buffer_size 4k;多域名证书配置:server { listen 443 ssl; server_name example.com www.example.com; ssl_certificate /etc/nginx/ssl/wildcard.crt; ssl_certificate_key /etc/nginx/ssl/wildcard.key; location / { root /var/www/html; }}证书链配置:如果证书需要中间证书,需要将证书和中间证书合并:cat example.com.crt intermediate.crt > bundle.crt然后在 Nginx 配置中使用 bundle.crt:ssl_certificate /etc/nginx/ssl/bundle.crt;
阅读 0·2月21日 16:57

Nginx 如何进行监控和运维?有哪些监控工具?

Nginx 如何进行监控和运维?有哪些监控工具?Nginx 的监控和运维对于保证服务稳定性和性能至关重要。合理的监控可以及时发现和解决问题。内置状态监控:# 启用 stub_status 模块server { listen 80; server_name localhost; location /nginx_status { stub_status on; access_log off; allow 127.0.0.1; deny all; }}状态信息说明:Active connections:当前活动连接数accepts:已接受的连接总数handled:已处理的连接总数requests:已处理的请求总数Reading:正在读取请求头的连接数Writing:正在发送响应的连接数Waiting:空闲连接数自定义监控端点:server { listen 80; server_name localhost; # 健康检查 location /health { access_log off; return 200 "OK\n"; add_header Content-Type text/plain; } # 就绪检查 location /ready { access_log off; # 检查后端连接 proxy_pass http://backend/health; proxy_intercept_errors off; } # 版本信息 location /version { access_log off; return 200 "Nginx/1.21.0\n"; add_header Content-Type text/plain; }}日志监控:# 自定义日志格式log_format monitoring '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' 'rt=$request_time uct="$upstream_connect_time" ' 'uht="$upstream_header_time" urt="$upstream_response_time" ' 'cache=$upstream_cache_status';server { listen 80; server_name example.com; access_log /var/log/nginx/monitoring.log monitoring; location / { proxy_pass http://backend; }}Prometheus 监控:# 安装 nginx-prometheus-exporter# https://github.com/nginxinc/nginx-prometheus-exporter# 配置 Nginxserver { listen 80; server_name localhost; location /metrics { proxy_pass http://localhost:9113/metrics; access_log off; allow 127.0.0.1; deny all; }}Grafana + Prometheus 监控:# prometheus.ymlglobal: scrape_interval: 15sscrape_configs: - job_name: 'nginx' static_configs: - targets: ['localhost:9113']ELK Stack 监控:# JSON 格式日志log_format json_combined escape=json '{' '"time_local":"$time_local",' '"remote_addr":"$remote_addr",' '"remote_user":"$remote_user",' '"request":"$request",' '"status":"$status",' '"body_bytes_sent":"$body_bytes_sent",' '"request_time":"$request_time",' '"http_referrer":"$http_referer",' '"http_user_agent":"$http_user_agent"''}';server { listen 80; server_name example.com; access_log /var/log/nginx/access.log json_combined; location / { proxy_pass http://backend; }}Zabbix 监控:# 安装 Zabbix Agent# 配置监控项# nginx_status[accepts]# nginx_status[handled]# nginx_status[requests]# nginx_status[reading]# nginx_status[writing]# nginx_status[waiting]性能监控指标:# 启用详细日志log_format performance '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' 'rt=$request_time ' 'uct=$upstream_connect_time ' 'uht=$upstream_header_time ' 'urt=$upstream_response_time ' 'cache=$upstream_cache_status';server { listen 80; server_name example.com; access_log /var/log/nginx/performance.log performance; location / { proxy_pass http://backend; }}告警配置:# 基于日志的告警map $status $alert_level { ~^[5] critical; ~^[4] warning; default ok;}server { listen 80; server_name example.com; access_log /var/log/nginx/access.log performance; location / { proxy_pass http://backend; # 添加告警头 add_header X-Alert-Level $alert_level; }}自动化运维脚本:#!/bin/bash# nginx_monitor.sh# 检查 Nginx 状态check_nginx_status() { if ! curl -f http://localhost/nginx_status > /dev/null 2>&1; then echo "Nginx status page is not accessible" return 1 fi return 0}# 检查进程check_nginx_process() { if ! pgrep -x nginx > /dev/null; then echo "Nginx process is not running" return 1 fi return 0}# 检查端口check_nginx_port() { if ! netstat -tlnp | grep :80 > /dev/null; then echo "Nginx is not listening on port 80" return 1 fi return 0}# 主函数main() { check_nginx_status check_nginx_process check_nginx_port echo "All checks passed"}main运维命令:# 重载配置(不中断服务)nginx -s reload# 优雅停止nginx -s quit# 快速停止nginx -s stop# 重新打开日志文件nginx -s reopen# 测试配置nginx -t# 查看版本nginx -v# 查看编译参数nginx -V日志轮转:# /etc/logrotate.d/nginx/var/log/nginx/*.log { daily missingok rotate 14 compress delaycompress notifempty create 0640 nginx adm sharedscripts postrotate [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid` endscript}完整监控配置示例:user nginx;worker_processes auto;http { # 日志格式 log_format main '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"'; log_format performance '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' 'rt=$request_time ' 'uct=$upstream_connect_time ' 'uht="$upstream_header_time" ' 'urt="$upstream_response_time" ' 'cache=$upstream_cache_status'; log_format json_combined escape=json '{' '"time_local":"$time_local",' '"remote_addr":"$remote_addr",' '"remote_user":"$remote_user",' '"request":"$request",' '"status":"$status",' '"body_bytes_sent":"$body_bytes_sent",' '"request_time":"$request_time",' '"http_referrer":"$http_referer",' '"http_user_agent":"$http_user_agent"' '}'; # 主站点 server { listen 80; server_name example.com; root /var/www/html; index index.html; # 性能日志 access_log /var/log/nginx/performance.log performance; error_log /var/log/nginx/error.log warn; # 监控端点 location /nginx_status { stub_status on; access_log off; allow 127.0.0.1; deny all; } location /health { access_log off; return 200 "OK\n"; add_header Content-Type text/plain; } location /ready { access_log off; proxy_pass http://backend/health; proxy_intercept_errors off; } location /metrics { proxy_pass http://localhost:9113/metrics; access_log off; allow 127.0.0.1; deny all; } location / { proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }}监控工具推荐:Prometheus + Grafana:强大的监控和可视化平台ELK Stack:日志收集、存储和分析Zabbix:企业级监控系统Nagios:成熟的监控解决方案Datadog:云端监控服务New Relic:应用性能监控AppDynamics:应用性能管理运维最佳实践:全面监控:监控性能、日志、资源使用及时告警:设置合理的告警阈值定期备份:备份配置和重要数据自动化运维:使用脚本和工具自动化运维文档记录:详细记录运维操作和问题定期演练:定期进行故障演练性能优化:持续监控和优化性能安全审计:定期进行安全检查容量规划:根据业务增长进行容量规划持续改进:根据监控数据持续改进
阅读 0·2月21日 16:57

Nginx 如何进行性能调优?有哪些关键参数?

Nginx 如何进行性能调优?有哪些关键参数?Nginx 性能调优是一个系统工程,需要从多个维度进行优化。合理的配置可以显著提升 Nginx 的处理能力和响应速度。核心配置优化:# 全局配置user nginx;worker_processes auto; # 自动设置为 CPU 核心数worker_rlimit_nofile 100000; # 文件描述符限制worker_cpu_affinity auto; # CPU 亲和性绑定events { worker_connections 65535; # 每个 worker 的最大连接数 use epoll; # Linux 使用 epoll multi_accept on; # 同时接受多个连接 accept_mutex off; # 关闭互斥锁,减少锁竞争}http { # 基础优化 sendfile on; # 启用高效文件传输 tcp_nopush on; # 优化数据包发送 tcp_nodelay on; # 禁用 Nagle 算法 keepalive_timeout 65; # 长连接超时 keepalive_requests 100; # 长连接最大请求数 # 缓冲区优化 client_body_buffer_size 128k; # 客户端请求体缓冲区 client_max_body_size 10m; # 最大请求体大小 client_header_buffer_size 1k; # 客户端请求头缓冲区 large_client_header_buffers 4 4k; # 大请求头缓冲区 # 输出缓冲 output_buffers 1 32k; # 输出缓冲区 postpone_output 1460; # 延迟输出 # 文件缓存 open_file_cache max=100000 inactive=20s; # 文件描述符缓存 open_file_cache_valid 30s; # 缓存验证间隔 open_file_cache_min_uses 2; # 最小使用次数 open_file_cache_errors on; # 缓存错误信息 # Gzip 压缩 gzip on; gzip_vary on; gzip_min_length 1024; gzip_comp_level 6; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss; gzip_disable "msie6";}Worker 进程优化:# 根据 CPU 核心数设置worker_processes auto;# 绑定 CPU 核心(手动设置)# 假设 4 核 CPUworker_processes 4;worker_cpu_affinity 0001 0010 0100 1000;# 设置工作进程优先级worker_priority -5; # -20 到 19,数值越小优先级越高连接优化:events { # 增加连接数 worker_connections 65535; # 同时接受多个连接 multi_accept on; # 关闭互斥锁(高并发时) accept_mutex off; # 使用高效的事件模型 use epoll; # Linux # use kqueue; # BSD/macOS}http { # 长连接优化 keepalive_timeout 65; keepalive_requests 100; # 上游服务器长连接 upstream backend { server 192.168.1.100:8080; keepalive 32; # 保持 32 个空闲连接 } # 代理超时设置 proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s;}缓冲区优化:http { # 客户端缓冲区 client_body_buffer_size 128k; client_max_body_size 10m; client_header_buffer_size 1k; large_client_header_buffers 4 4k; # 代理缓冲区 proxy_buffering on; proxy_buffer_size 4k; proxy_buffers 8 4k; proxy_busy_buffers_size 8k; # FastCGI 缓冲区 fastcgi_buffer_size 4k; fastcgi_buffers 8 4k; # 输出缓冲 output_buffers 1 32k; postpone_output 1460;}文件操作优化:http { # 文件缓存 open_file_cache max=100000 inactive=20s; open_file_cache_valid 30s; open_file_cache_min_uses 2; open_file_cache_errors on; # 高效文件传输 sendfile on; tcp_nopush on; tcp_nodelay on; # 直接 I/O(大文件) # directio 4m;}压缩优化:http { gzip on; gzip_vary on; gzip_min_length 1024; # 最小压缩文件大小 gzip_comp_level 6; # 压缩级别 1-9 gzip_buffers 16 8k; # 压缩缓冲区 gzip_http_version 1.1; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/rss+xml application/atom+xml image/svg+xml; gzip_disable "msie6"; # 静态资源预压缩 gzip_static on;}日志优化:http { # 自定义日志格式 log_format main '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' 'rt=$request_time uct="$upstream_connect_time" ' 'uht="$upstream_header_time" urt="$upstream_response_time"'; # 访问日志 access_log /var/log/nginx/access.log main buffer=32k flush=5s; # 错误日志 error_log /var/log/nginx/error.log warn; # 关闭静态资源日志 location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ { access_log off; }}SSL/TLS 优化:server { listen 443 ssl http2; # SSL 会话缓存 ssl_session_cache shared:SSL:50m; ssl_session_timeout 1d; ssl_session_tickets off; # SSL 缓冲区 ssl_buffer_size 4k; # 协议和加密套件 ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256; ssl_prefer_server_ciphers on; # OCSP Stapling ssl_stapling on; ssl_stapling_verify on;}系统级优化:# /etc/sysctl.conf# 文件描述符fs.file-max = 1000000# TCP 参数net.ipv4.tcp_max_tw_buckets = 6000net.ipv4.tcp_sack = 1net.ipv4.tcp_window_scaling = 1net.ipv4.tcp_rmem = 4096 87380 4194304net.ipv4.tcp_wmem = 4096 65536 4194304net.core.rmem_max = 16777216net.core.wmem_max = 16777216net.core.netdev_max_backlog = 262144net.ipv4.tcp_max_syn_backlog = 262144net.ipv4.tcp_fin_timeout = 30net.ipv4.tcp_keepalive_time = 1200net.ipv4.tcp_tw_reuse = 1# 应用配置sysctl -p用户限制:# /etc/security/limits.confnginx soft nofile 65535nginx hard nofile 65535监控和诊断:# 状态监控location /nginx_status { stub_status on; access_log off; allow 127.0.0.1; deny all;}# 请求追踪location /debug { add_header X-Request-ID $request_id; add_header X-Upstream-Addr $upstream_addr;}性能测试工具:# wrk 压力测试wrk -t12 -c4000 -d30s http://example.com/# ab 压力测试ab -n 10000 -c 1000 http://example.com/# siege 压力测试siege -c 100 -t 60S http://example.com/关键性能指标:QPS(每秒查询数):衡量处理能力响应时间:平均、P95、P99并发连接数:当前活动连接错误率:4xx、5xx 错误比例CPU 使用率:不应持续超过 70%内存使用:监控内存占用磁盘 I/O:监控读写性能调优建议:渐进式调优:每次只调整一个参数,观察效果基准测试:调优前后进行性能对比监控指标:持续关注关键性能指标日志分析:分析访问日志发现瓶颈定期审查:定期检查配置是否合理
阅读 0·2月21日 16:57

Nginx 如何进行安全配置?有哪些安全最佳实践?

Nginx 如何进行安全配置?有哪些安全最佳实践?Nginx 的安全配置对于保护 Web 服务器免受各种攻击至关重要。合理的安全配置可以有效防止常见的安全威胁。基础安全配置:# 隐藏 Nginx 版本号server_tokens off;# 限制请求方法if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 405;}# 限制请求体大小client_max_body_size 10m;# 限制请求头大小client_header_buffer_size 1k;large_client_header_buffers 4 4k;# 超时设置client_body_timeout 10;client_header_timeout 10;keepalive_timeout 5 5;send_timeout 10;防止常见攻击:1. 防止 SQL 注入:location ~* \.(php|jsp|asp)$ { if ($args ~* "union.*select.*\(") { return 403; } if ($args ~* "concat.*\(") { return 403; }}2. 防止 XSS 攻击:location ~* \.(php|html|htm)$ { if ($args ~* "<script>|</script>|javascript:|onerror=|onload=|onclick=") { return 403; }}3. 防止文件包含攻击:location ~* \.(php|inc|config)$ { if ($args ~* "\.\./") { return 403; }}4. 防止目录遍历:location ~* /\.\. { deny all;}访问控制:# IP 白名单location /admin { allow 192.168.1.0/24; allow 10.0.0.0/8; deny all;}# IP 黑名单location / { deny 192.168.1.100; deny 192.168.1.101; allow all;}# 基本认证location /admin { auth_basic "Restricted Area"; auth_basic_user_file /etc/nginx/.htpasswd;}防止 DDoS 攻击:# 限制连接数limit_conn_zone $binary_remote_addr zone=conn_limit:10m;server { limit_conn conn_limit 10; # 限制请求速率 limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s; limit_req zone=req_limit burst=20 nodelay; # 限制带宽 limit_rate_after 10m; limit_rate 1m;}SSL/TLS 安全配置:server { listen 443 ssl http2; server_name example.com; # 证书配置 ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; # SSL 协议 ssl_protocols TLSv1.2 TLSv1.3; # 加密套件 ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers on; # SSL 会话缓存 ssl_session_cache shared:SSL:50m; ssl_session_timeout 1d; ssl_session_tickets off; # OCSP Stapling ssl_stapling on; ssl_stapling_verify on; ssl_trusted_certificate /etc/nginx/ssl/chain.crt; # HSTS add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # 其他安全头 add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';" always;}文件安全:# 禁止访问隐藏文件location ~ /\. { deny all; access_log off; log_not_found off;}# 禁止访问敏感文件location ~* \.(htaccess|htpasswd|ini|log|sh|sql|bak|old|swp|tmp)$ { deny all; access_log off; log_not_found off;}# 禁止访问备份文件location ~* \~$ { deny all; access_log off; log_not_found off;}# 禁止目录浏览autoindex off;# 禁止访问特定目录location ~* ^/(admin|config|backup|tmp)/ { deny all;}防止恶意 User-Agent:# 阻止恶意爬虫if ($http_user_agent ~* (bot|crawl|spider|scraper)) { return 403;}# 阻止特定 User-Agentif ($http_user_agent ~* (wget|curl|python-requests)) { return 403;}防止图片盗链:location ~* \.(jpg|jpeg|png|gif|ico|svg)$ { valid_referers none blocked example.com *.example.com; if ($invalid_referer) { return 403; }}日志安全:# 自定义日志格式,记录更多安全信息log_format security '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$request_time $upstream_response_time ' '$http_x_forwarded_for';# 访问日志access_log /var/log/nginx/access.log security;# 错误日志error_log /var/log/nginx/error.log warn;# 敏感路径不记录日志location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ { access_log off;}防止缓冲区溢出:# 限制缓冲区大小client_body_buffer_size 128k;client_header_buffer_size 1k;large_client_header_buffers 4 4k;client_max_body_size 10m;# 代理缓冲区proxy_buffer_size 4k;proxy_buffers 8 4k;proxy_busy_buffers_size 8k;安全最佳实践:定期更新:保持 Nginx 和系统补丁最新最小权限原则:使用非 root 用户运行 Nginx禁用不必要的模块:减少攻击面配置防火墙:限制不必要的端口访问使用 HTTPS:启用 SSL/TLS 加密定期审计日志:监控异常访问实施 WAF:使用 Web 应用防火墙备份配置:定期备份配置文件测试配置:使用 nginx -t 测试配置监控性能:使用监控工具跟踪性能指标完整安全配置示例:user nginx;worker_processes auto;worker_rlimit_nofile 65535;# 隐藏版本号server_tokens off;events { worker_connections 1024; use epoll;}http { # 基础安全 client_max_body_size 10m; client_header_buffer_size 1k; large_client_header_buffers 4 4k; # 超时设置 client_body_timeout 10; client_header_timeout 10; keepalive_timeout 5 5; send_timeout 10; # 限流 limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s; limit_conn_zone $binary_remote_addr zone=conn_limit:10m; # 日志 log_format security '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"'; access_log /var/log/nginx/access.log security; error_log /var/log/nginx/error.log warn; # Gzip gzip on; gzip_vary on; gzip_min_length 1024; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript; server { listen 80; server_name example.com; # 重定向到 HTTPS return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name example.com; # SSL 配置 ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:50m; ssl_session_timeout 1d; # 安全头 add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; # 限流 limit_req zone=req_limit burst=20 nodelay; limit_conn conn_limit 10; # 禁止访问隐藏文件 location ~ /\. { deny all; access_log off; } # 禁止访问敏感文件 location ~* \.(htaccess|htpasswd|ini|log|sh|sql|bak|old|swp|tmp)$ { deny all; access_log off; } # 管理后台访问控制 location /admin { allow 192.168.1.0/24; deny all; auth_basic "Restricted"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass http://backend; } # 主站点 location / { proxy_pass http://backend; 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; } }}
阅读 0·2月21日 16:57

Nginx 如何实现限流?有哪些限流策略?

Nginx 如何实现限流?有哪些限流策略?Nginx 提供了强大的限流功能,可以有效防止 DDoS 攻击、保护服务器资源、防止恶意请求。Nginx 的限流主要通过 limit_req 和 limit_conn 模块实现。请求速率限制(limit_req):http { # 定义限流区域,基于客户端 IP limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s; # 定义限流区域,基于请求 URI limit_req_zone $request_uri zone=uri:10m rate=5r/s; # 定义限流区域,基于服务器名称 limit_req_zone $server_name zone=server:10m rate=100r/s; server { listen 80; server_name example.com; # 应用限流 location / { limit_req zone=one burst=20 nodelay; proxy_pass http://backend; } # API 接口限流 location /api/ { limit_req zone=one burst=10 nodelay; limit_req_status 429; proxy_pass http://api_backend; } }}参数说明:limitreqzone:定义限流区域$binary_remote_addr:客户端 IP 地址(二进制格式,节省内存)zone=one:10m:区域名称和共享内存大小(10M 可存储约 16 万个 IP)rate=10r/s:每秒允许 10 个请求limit_req:应用限流规则zone=one:使用的限流区域burst=20:允许的突发请求数nodelay:不延迟处理突发请求limitreqstatus:超过限制时返回的状态码(默认 503)连接数限制(limit_conn):http { # 定义连接数限制区域 limit_conn_zone $binary_remote_addr zone=addr:10m; # 定义服务器连接数限制区域 limit_conn_zone $server_name zone=server:10m; server { listen 80; server_name example.com; # 限制每个 IP 的并发连接数 limit_conn addr 10; # 限制服务器的总连接数 limit_conn server 1000; location / { proxy_pass http://backend; } }}带宽限制:server { listen 80; server_name example.com; location /download/ { # 限制下载速度为 1MB/s limit_rate 1m; # 前 10MB 不限速 limit_rate_after 10m; root /var/www/files; }}综合限流配置:http { # 请求速率限制 limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s; limit_req_zone $request_uri zone=uri_limit:10m rate=5r/s; # 连接数限制 limit_conn_zone $binary_remote_addr zone=conn_limit:10m; # 状态码限制 limit_req_status 429; limit_conn_status 429; server { listen 80; server_name example.com; # 全局限流 limit_conn conn_limit 10; # 首页限流 location = / { limit_req zone=req_limit burst=20 nodelay; proxy_pass http://backend; } # API 接口严格限流 location /api/ { limit_req zone=req_limit burst=5 nodelay; limit_req zone=uri_limit burst=2 nodelay; proxy_pass http://api_backend; } # 下载限速 location /download/ { limit_rate 1m; limit_rate_after 10m; root /var/www/files; } # 静态资源不限流 location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ { root /var/www/static; } }}白名单配置:http { # 定义限流区域 limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s; # 定义白名单 geo $limit_key { default $binary_remote_addr; 192.168.1.0/24 ""; 10.0.0.0/8 ""; } # 基于白名单的限流 limit_req_zone $limit_key zone=whitelist_limit:10m rate=10r/s; server { listen 80; server_name example.com; location / { limit_req zone=whitelist_limit burst=20 nodelay; proxy_pass http://backend; } }}动态限流:http { # 根据请求方法限流 map $request_method $limit_key { default $binary_remote_addr; GET ""; HEAD ""; } limit_req_zone $limit_key zone=dynamic_limit:10m rate=10r/s; server { listen 80; server_name example.com; location / { limit_req zone=dynamic_limit burst=20 nodelay; proxy_pass http://backend; } }}限流日志:http { # 自定义日志格式,包含限流信息 log_format limit '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' 'rt=$request_time limit=$limit_req_status'; access_log /var/log/nginx/access.log limit; # 限流区域 limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s; server { listen 80; server_name example.com; location / { limit_req zone=req_limit burst=20 nodelay; limit_req_log_level warn; proxy_pass http://backend; } }}限流策略选择:固定窗口限流:rate=10r/s,每秒固定请求数滑动窗口限流:通过 burst 参数实现令牌桶算法:Nginx 默认使用,允许突发流量漏桶算法:通过 nodelay 参数控制实际应用场景:1. API 接口限流:limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/min;location /api/ { limit_req zone=api_limit burst=10 nodelay; limit_req_status 429; add_header X-RateLimit-Limit "100"; add_header X-RateLimit-Remaining "90"; add_header X-RateLimit-Reset "60"; proxy_pass http://api_backend;}2. 登录接口限流:limit_req_zone $binary_remote_addr zone=login_limit:10m rate=5r/min;location /login { limit_req zone=login_limit burst=2 nodelay; limit_req_status 429; proxy_pass http://auth_backend;}3. 文件下载限速:location /download/ { limit_rate 500k; limit_rate_after 5m; root /var/www/files;}4. 防止暴力破解:limit_req_zone $binary_remote_addr zone=auth_limit:10m rate=3r/min;location ~* ^/(login|register|reset-password) { limit_req zone=auth_limit burst=1 nodelay; limit_req_status 429; proxy_pass http://auth_backend;}监控和调试:# 启用限流状态监控location /limit_status { limit_req_status 429; add_header Content-Type text/plain; return 200 "Rate limit status: $limit_req_status";}# 查看限流统计location /nginx_status { stub_status on; access_log off; allow 127.0.0.1; deny all;}最佳实践:合理设置速率:根据业务需求设置合理的限流速率使用 burst:允许一定程度的突发流量返回友好错误:设置 429 状态码,返回友好提示白名单机制:对可信 IP 放开限流监控限流效果:定期检查限流日志,调整策略分层限流:对不同接口设置不同的限流策略结合缓存:对静态资源使用缓存,减少限流压力性能考虑:共享内存大小:根据 IP 数量合理设置 zone 大小限流粒度:选择合适的限流键(IP、URI 等)日志级别:生产环境使用 warn 级别,减少日志量nodelay 使用:根据场景选择是否使用 nodelay
阅读 0·2月21日 16:57

Nginx 如何实现访问控制?有哪些访问控制方法?

Nginx 如何实现访问控制?有哪些访问控制方法?Nginx 提供了多种访问控制方法,包括基于 IP 的访问控制、基本认证、访问令牌等,可以有效保护敏感资源。IP 访问控制:server { listen 80; server_name example.com; # IP 白名单 location /admin { allow 192.168.1.0/24; allow 10.0.0.0/8; deny all; proxy_pass http://backend; } # IP 黑名单 location / { deny 192.168.1.100; deny 192.168.1.101; allow all; proxy_pass http://backend; }}基本认证:server { listen 80; server_name example.com; # 创建密码文件 # htpasswd -c /etc/nginx/.htpasswd username location /admin { auth_basic "Restricted Area"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass http://backend; } # 多用户认证 location /api { auth_basic "API Access"; auth_basic_user_file /etc/nginx/.htpasswd_api; proxy_pass http://api_backend; }}访问令牌:server { listen 80; server_name example.com; # 基于 Header 的访问控制 location /api { if ($http_authorization !~* "Bearer .*") { return 401; } proxy_pass http://api_backend; } # 基于查询参数的访问控制 location /protected { if ($arg_token != "secret_token") { return 403; } proxy_pass http://backend; }}地理位置访问控制:http { # 定义地理位置映射 geo $allowed_country { default no; CN yes; US yes; } server { listen 80; server_name example.com; location / { if ($allowed_country = no) { return 403; } proxy_pass http://backend; } }}基于请求方法的访问控制:server { listen 80; server_name example.com; # 限制允许的请求方法 if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 405; } # 特定路径只允许特定方法 location /api { if ($request_method !~ ^(GET|POST)$ ) { return 405; } proxy_pass http://api_backend; } # 只读接口 location /api/read { if ($request_method !~ ^(GET|HEAD)$ ) { return 405; } proxy_pass http://api_backend; }}基于请求头的访问控制:server { listen 80; server_name example.com; # 检查特定的请求头 location /api { if ($http_x_api_key = "") { return 401; } proxy_pass http://api_backend; } # 检查 User-Agent location / { if ($http_user_agent ~* (bot|crawl|spider)) { return 403; } proxy_pass http://backend; } # 检查 Referer location /download { valid_referers none blocked example.com *.example.com; if ($invalid_referer) { return 403; } root /var/www/files; }}复杂访问控制:http { # 定义多个访问控制变量 geo $whitelist { default 0; 192.168.1.0/24 1; 10.0.0.0/8 1; } map $http_x_api_key $api_valid { default 0; "secret_key_123" 1; "secret_key_456" 1; } server { listen 80; server_name example.com; # 组合多个访问控制条件 location /admin { # IP 白名单 allow 192.168.1.0/24; allow 10.0.0.0/8; deny all; # 基本认证 auth_basic "Admin Area"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass http://backend; } # API 访问控制 location /api { # 检查 API Key if ($api_valid = 0) { return 401; } # 限制请求方法 if ($request_method !~ ^(GET|POST|PUT|DELETE)$ ) { return 405; } proxy_pass http://api_backend; } # 静态资源访问控制 location /protected { # IP 白名单或认证 satisfy any; allow 192.168.1.0/24; deny all; auth_basic "Protected Area"; auth_basic_user_file /etc/nginx/.htpasswd; root /var/www/protected; } }}基于时间的访问控制:http { # 定义时间段 map $time_iso8601 $business_hours { default 0; ~^(\d{4}-\d{2}-\d{2}T(09|1[0-9]|2[0-1])) 1; } server { listen 80; server_name example.com; # 只在工作时间允许访问 location /admin { if ($business_hours = 0) { return 403; } proxy_pass http://backend; } }}防止目录遍历:server { listen 80; server_name example.com; # 禁止访问父目录 location ~* /\.\. { deny all; } # 禁止访问隐藏文件 location ~ /\. { deny all; access_log off; log_not_found off; } # 禁止目录浏览 autoindex off; location / { proxy_pass http://backend; }}限制文件类型访问:server { listen 80; server_name example.com; # 禁止访问敏感文件 location ~* \.(htaccess|htpasswd|ini|log|sh|sql|bak|old|swp|tmp)$ { deny all; access_log off; log_not_found off; } # 只允许特定文件类型 location /uploads { location ~* \.(jpg|jpeg|png|gif|pdf|doc|docx)$ { root /var/www/uploads; } location ~* \.(php|sh|exe|bat)$ { deny all; } }}访问控制最佳实践:最小权限原则:只授予必要的访问权限多层防护:组合使用多种访问控制方法定期审查:定期检查和更新访问控制规则日志记录:记录所有访问控制事件白名单优先:优先使用白名单而非黑名单测试配置:在生产环境前充分测试访问控制规则监控异常:监控异常访问行为及时更新:及时更新密码和访问令牌完整访问控制配置示例:http { # IP 白名单 geo $whitelist { default 0; 192.168.1.0/24 1; 10.0.0.0/8 1; } # API Key 验证 map $http_x_api_key $api_valid { default 0; "secret_key_123" 1; "secret_key_456" 1; } # 工作时间 map $time_iso8601 $business_hours { default 0; ~^(\d{4}-\d{2}-\d{2}T(09|1[0-9]|2[0-1])) 1; } server { listen 80; server_name example.com; # 管理后台 location /admin { # IP 白名单 allow 192.168.1.0/24; allow 10.0.0.0/8; deny all; # 基本认证 auth_basic "Admin Area"; auth_basic_user_file /etc/nginx/.htpasswd; # 工作时间限制 if ($business_hours = 0) { return 403; } proxy_pass http://backend; } # API 接口 location /api { # API Key 验证 if ($api_valid = 0) { return 401; } # 限制请求方法 if ($request_method !~ ^(GET|POST|PUT|DELETE)$ ) { return 405; } # 限流 limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/min; limit_req zone=api_limit burst=10 nodelay; proxy_pass http://api_backend; } # 受保护资源 location /protected { # IP 白名单或认证 satisfy any; allow 192.168.1.0/24; deny all; auth_basic "Protected Area"; auth_basic_user_file /etc/nginx/.htpasswd; root /var/www/protected; } # 禁止访问敏感文件 location ~* \.(htaccess|htpasswd|ini|log|sh|sql|bak|old|swp|tmp)$ { deny all; access_log off; log_not_found off; } # 禁止目录遍历 location ~* /\.\. { deny all; } # 禁止访问隐藏文件 location ~ /\. { deny all; access_log off; log_not_found off; } # 主站点 location / { proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }}
阅读 0·2月21日 16:57

Nginx 如何实现缓存?如何配置缓存策略?

Nginx 如何实现缓存?如何配置缓存策略?Nginx 提供了强大的缓存功能,可以缓存后端服务器的响应,减轻后端负载,提高响应速度。Nginx 支持代理缓存和 FastCGI 缓存等多种缓存方式。代理缓存配置:http { # 定义缓存路径和参数 proxy_cache_path /var/cache/nginx/proxy levels=1:2 keys_zone=proxy_cache:10m max_size=1g inactive=60m use_temp_path=off; server { listen 80; server_name example.com; location / { proxy_cache proxy_cache; proxy_cache_valid 200 302 10m; proxy_cache_valid 404 1m; proxy_cache_key "$scheme$request_method$host$request_uri"; proxy_cache_bypass $http_cache_control; add_header X-Cache-Status $upstream_cache_status; proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }}缓存参数说明:proxycachepath:定义缓存存储路径和参数levels:缓存目录层级结构keys_zone:共享内存区域名称和大小max_size:缓存最大大小inactive:缓存项不活动时间use_temp_path:是否使用临时路径proxy_cache:指定使用的缓存区域proxycachevalid:设置不同状态码的缓存时间200 302 10m:200 和 302 状态码缓存 10 分钟404 1m:404 状态码缓存 1 分钟proxycachekey:定义缓存键proxycachebypass:绕过缓存的条件FastCGI 缓存配置:http { fastcgi_cache_path /var/cache/nginx/fastcgi levels=1:2 keys_zone=fastcgi_cache:10m max_size=1g inactive=60m; server { listen 80; server_name example.com; location ~ \.php$ { fastcgi_cache fastcgi_cache; fastcgi_cache_valid 200 60m; fastcgi_cache_methods GET HEAD; fastcgi_cache_bypass $skip_cache; fastcgi_no_cache $skip_cache; add_header X-Cache-Status $upstream_cache_status; fastcgi_pass unix:/var/run/php/php8.0-fpm.sock; fastcgi_index index.php; include fastcgi_params; } }}缓存清除:Nginx 开源版本不支持主动缓存清除,可以通过以下方式实现:设置缓存过期时间:通过 proxy_cache_valid 控制使用第三方模块:如 ngxcachepurge手动删除缓存文件:根据缓存键删除对应文件缓存策略配置:# 根据请求方法缓存proxy_cache_methods GET HEAD;# 根据响应头缓存proxy_ignore_headers X-Accel-Expires Expires Cache-Control Set-Cookie;# 缓存最小请求次数proxy_cache_min_uses 2;# 缓存锁定,防止缓存风暴proxy_cache_lock on;proxy_cache_lock_timeout 5s;# 缓存背景更新proxy_cache_background_update on;proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;动态缓存控制:# 根据条件决定是否缓存map $request_uri $skip_cache { default 0; ~*/admin/ 1; ~*/api/ 1;}# 根据响应头决定是否缓存map $upstream_http_cache_control $skip_cache { ~*no-cache 1; ~*private 1; default 0;}静态文件缓存:location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ { expires 1y; add_header Cache-Control "public, immutable"; access_log off;}缓存状态监控:add_header X-Cache-Status $upstream_cache_status;# 缓存状态值:# MISS - 未命中缓存# BYPASS - 绕过缓存# EXPIRED - 缓存过期# STALE - 使用过期缓存# UPDATING - 缓存更新中# HIT - 命中缓存缓存优化建议:合理设置缓存时间,平衡新鲜度和性能使用缓存键包含必要参数,避免缓存冲突对动态内容禁用缓存定期清理过期缓存监控缓存命中率,调整缓存策略使用缓存锁定防止缓存风暴对静态资源使用浏览器缓存完整配置示例:http { # 代理缓存 proxy_cache_path /var/cache/nginx/proxy levels=1:2 keys_zone=proxy_cache:100m max_size=10g inactive=60m use_temp_path=off; # FastCGI 缓存 fastcgi_cache_path /var/cache/nginx/fastcgi levels=1:2 keys_zone=fastcgi_cache:100m max_size=10g inactive=60m; # 缓存跳过条件 map $request_uri $skip_cache { default 0; ~*/admin/ 1; ~*/api/ 1; ~*/user/ 1; } server { listen 80; server_name example.com; # 静态文件 location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ { expires 1y; add_header Cache-Control "public, immutable"; } # 动态内容代理 location / { proxy_cache proxy_cache; proxy_cache_valid 200 302 10m; proxy_cache_valid 404 1m; proxy_cache_key "$scheme$request_method$host$request_uri"; proxy_cache_bypass $skip_cache; proxy_no_cache $skip_cache; add_header X-Cache-Status $upstream_cache_status; proxy_pass http://backend; } # PHP 文件 location ~ \.php$ { fastcgi_cache fastcgi_cache; fastcgi_cache_valid 200 60m; fastcgi_cache_bypass $skip_cache; fastcgi_no_cache $skip_cache; add_header X-Cache-Status $upstream_cache_status; fastcgi_pass unix:/var/run/php/php8.0-fpm.sock; } }}
阅读 0·2月21日 16:57

Nginx 的 location 指令如何匹配?优先级是什么?

Nginx 的 location 指令如何匹配?优先级是什么?Nginx 的 location 指令用于匹配请求的 URI,并定义如何处理这些请求。理解 location 的匹配规则和优先级对于正确配置 Nginx 至关重要。Location 匹配规则:1. 精确匹配(=)使用 = 进行精确匹配,如果匹配成功,立即停止搜索并使用该 location。location = /exact { # 精确匹配 /exact}2. 前缀匹配(无修饰符)不使用任何修饰符,按前缀匹配,匹配成功后继续搜索更精确的匹配。location /prefix { # 匹配以 /prefix 开头的 URI}3. 正则匹配(~ 和 ~*)~:区分大小写的正则匹配~*:不区分大小写的正则匹配location ~ \.php$ { # 匹配以 .php 结尾的 URI(区分大小写)}location ~* \.(jpg|jpeg|png|gif)$ { # 匹配图片文件(不区分大小写)}4. 前缀匹配(^~)使用 ^~ 进行前缀匹配,如果匹配成功,立即停止搜索,不再检查正则表达式。location ^~ /static/ { # 匹配以 /static/ 开头的 URI,不再检查正则}匹配优先级(从高到低):精确匹配(=):优先级最高前缀匹配(^~):如果匹配成功,停止搜索正则匹配(~ 和 ~*):按配置顺序依次检查前缀匹配(无修饰符):优先级最低匹配示例:server { listen 80; server_name example.com; # 1. 精确匹配 location = / { return 200 "Exact match /"; } # 2. ^~ 前缀匹配 location ^~ /images/ { return 200 "Prefix match ^~ /images/"; } # 3. 正则匹配(区分大小写) location ~ \.php$ { return 200 "Regex match .php"; } # 4. 正则匹配(不区分大小写) location ~* \.(jpg|jpeg|png|gif)$ { return 200 "Regex match images"; } # 5. 普通前缀匹配 location / { return 200 "Prefix match /"; }}实际匹配结果:请求 / → 精确匹配 location = /请求 /images/logo.jpg → location ^~ /images/(停止搜索,不匹配正则)请求 /test.php → location ~ \.php$请求 /photo.JPG → location ~* \.(jpg|jpeg|png|gif)$(不区分大小写)请求 /other → location /嵌套 Location:location /api/ { # 外层 location proxy_pass http://backend; location /api/v1/ { # 内层 location,继承外层配置 proxy_pass http://backend_v1; }}使用建议:将精确匹配放在最前面将正则匹配放在中间将普通前缀匹配放在最后使用 ^~ 避免不必要的正则匹配合理使用正则匹配,避免过度使用影响性能性能考虑:精确匹配和 ^~ 匹配性能最好正则匹配需要编译和执行,性能相对较低避免使用复杂的正则表达式正则匹配按配置顺序执行,将常用匹配放在前面实际应用场景:# 静态文件缓存location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg)$ { expires 1y; add_header Cache-Control "public, immutable";}# PHP 文件处理location ~ \.php$ { fastcgi_pass unix:/var/run/php/php8.0-fpm.sock; fastcgi_index index.php; include fastcgi_params;}# API 请求代理location /api/ { proxy_pass http://api_backend;}# 管理后台location ^~ /admin/ { auth_basic "Restricted"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass http://admin_backend;}
阅读 0·2月21日 16:56

Nginx 如何配置虚拟主机?有哪些配置方式?

Nginx 如何配置虚拟主机?有哪些配置方式?Nginx 虚拟主机(Virtual Host)允许在同一台服务器上运行多个网站,通过不同的域名、端口或 IP 地址来区分不同的站点。基于域名的虚拟主机:server { listen 80; server_name example.com www.example.com; root /var/www/example.com; index index.html index.php; access_log /var/log/nginx/example.com.access.log; error_log /var/log/nginx/example.com.error.log; location / { try_files $uri $uri/ =404; }}server { listen 80; server_name test.com www.test.com; root /var/www/test.com; index index.html index.php; access_log /var/log/nginx/test.com.access.log; error_log /var/log/nginx/test.com.error.log; location / { try_files $uri $uri/ =404; }}基于端口的虚拟主机:server { listen 80; server_name example.com; root /var/www/example.com; index index.html; location / { try_files $uri $uri/ =404; }}server { listen 8080; server_name example.com; root /var/www/example.com/admin; index index.html; location / { try_files $uri $uri/ =404; }}server { listen 8443 ssl; server_name example.com; ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; root /var/www/example.com/secure; index index.html; location / { try_files $uri $uri/ =404; }}基于 IP 地址的虚拟主机:server { listen 192.168.1.100:80; server_name example.com; root /var/www/example.com; index index.html; location / { try_files $uri $uri/ =404; }}server { listen 192.168.1.101:80; server_name example.com; root /var/www/example.com/mirror; index index.html; location / { try_files $uri $uri/ =404; }}通配符域名:# 匹配所有子域名server { listen 80; server_name *.example.com; root /var/www/subdomains; index index.html; location / { # 使用子域名作为目录名 set $subdomain $host; if ($subdomain ~* ^(.*)\.example\.com$) { set $subdomain $1; } root /var/www/subdomains/$subdomain; }}# 匹配所有域名(默认虚拟主机)server { listen 80 default_server; server_name _; root /var/www/default; index index.html; location / { return 404; }}正则表达式域名:server { listen 80; server_name ~^(?<subdomain>.+)\.example\.com$; root /var/www/example.com/$subdomain; index index.html; location / { try_files $uri $uri/ =404; }}server { listen 80; server_name ~^(?<user>.+)\.users\.example\.com$; root /var/www/users/$user; index index.html; location / { try_files $uri $uri/ =404; }}HTTPS 虚拟主机:server { listen 80; server_name example.com; # 重定向到 HTTPS return 301 https://$server_name$request_uri;}server { listen 443 ssl http2; server_name example.com; ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; root /var/www/example.com; index index.html; location / { try_files $uri $uri/ =404; }}多域名共享配置:# 定义共享配置map $host $root_path { example.com /var/www/example.com; test.com /var/www/test.com; default /var/www/default;}server { listen 80; server_name example.com test.com; root $root_path; index index.html; location / { try_files $uri $uri/ =404; }}反向代理虚拟主机:upstream backend1 { server 192.168.1.100:8080; server 192.168.1.101:8080;}upstream backend2 { server 192.168.1.200:8080; server 192.168.1.201:8080;}server { listen 80; server_name api.example.com; location / { proxy_pass http://backend1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }}server { listen 80; server_name admin.example.com; location / { proxy_pass http://backend2; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }}PHP 虚拟主机:server { listen 80; server_name example.com; root /var/www/example.com; index index.php index.html; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass unix:/var/run/php/php8.0-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ { expires 1y; add_header Cache-Control "public, immutable"; }}静态站点虚拟主机:server { listen 80; server_name static.example.com; root /var/www/static; index index.html; # 启用 Gzip 压缩 gzip on; gzip_vary on; gzip_min_length 1024; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript; # 静态资源缓存 location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ { expires 1y; add_header Cache-Control "public, immutable"; access_log off; } location / { try_files $uri $uri/ =404; }}虚拟主机配置文件分离:# /etc/nginx/nginx.confhttp { include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*;}# /etc/nginx/sites-available/example.comserver { listen 80; server_name example.com; root /var/www/example.com; index index.html; location / { try_files $uri $uri/ =404; }}# 创建符号链接启用站点# ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com虚拟主机最佳实践:配置文件分离:每个虚拟主机使用独立的配置文件命名规范:使用域名作为配置文件名日志分离:每个虚拟主机使用独立的日志文件默认主机:配置 default_server 处理未知请求SSL 配置:所有生产环境使用 HTTPS错误页面:为每个虚拟主机配置自定义错误页面安全头:添加安全相关的 HTTP 头性能优化:启用 Gzip 压缩和缓存完整虚拟主机配置示例:# /etc/nginx/sites-available/example.comserver { listen 80; server_name example.com www.example.com; # 重定向到 HTTPS return 301 https://$server_name$request_uri;}server { listen 443 ssl http2; server_name example.com www.example.com; # SSL 配置 ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # 根目录 root /var/www/example.com; index index.php index.html; # 日志 access_log /var/log/nginx/example.com.access.log; error_log /var/log/nginx/example.com.error.log; # 安全头 add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; # Gzip 压缩 gzip on; gzip_vary on; gzip_min_length 1024; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript; # 静态资源 location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ { expires 1y; add_header Cache-Control "public, immutable"; access_log off; } # PHP 处理 location ~ \.php$ { fastcgi_pass unix:/var/run/php/php8.0-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } # 主路由 location / { try_files $uri $uri/ /index.php?$query_string; } # 禁止访问隐藏文件 location ~ /\. { deny all; access_log off; log_not_found off; }}
阅读 0·2月21日 16:56

RxJS 在 Angular 中如何应用?

RxJS 在 Angular 中的应用RxJS 是 Angular 框架的核心依赖,广泛应用于异步操作、事件处理和数据流管理。核心应用场景1. HTTP 请求Angular 的 HttpClient 返回 Observable,便于处理异步请求。import { HttpClient } from '@angular/common/http';import { Observable } from 'rxjs';@Injectable({ providedIn: 'root'})export class DataService { constructor(private http: HttpClient) {} getUsers(): Observable<User[]> { return this.http.get<User[]>('/api/users'); } getUserById(id: number): Observable<User> { return this.http.get<User>(`/api/users/${id}`); } createUser(user: User): Observable<User> { return this.http.post<User>('/api/users', user); } updateUser(id: number, user: User): Observable<User> { return this.http.put<User>(`/api/users/${id}`, user); } deleteUser(id: number): Observable<void> { return this.http.delete<void>(`/api/users/${id}`); }}在组件中使用:import { Component, OnInit } from '@angular/core';import { DataService } from './data.service';@Component({ selector: 'app-user-list', template: ` <div *ngIf="users$ | async as users"> <div *ngFor="let user of users"> {{ user.name }} </div> </div> `})export class UserListComponent implements OnInit { users$: Observable<User[]>; constructor(private dataService: DataService) {} ngOnInit() { this.users$ = this.dataService.getUsers(); }}2. 表单处理Angular 的响应式表单与 RxJS 完美集成。import { Component, OnInit } from '@angular/core';import { FormBuilder, FormGroup, Validators } from '@angular/forms';@Component({ selector: 'app-search-form', template: ` <form [formGroup]="searchForm"> <input formControlName="search" placeholder="Search..."> </form> `})export class SearchFormComponent implements OnInit { searchForm: FormGroup; constructor(private fb: FormBuilder) { this.searchForm = this.fb.group({ search: ['', Validators.minLength(3)] }); } ngOnInit() { // 监听搜索输入 this.searchForm.get('search')?.valueChanges.pipe( debounceTime(300), distinctUntilChanged(), filter(query => query.length >= 3), switchMap(query => this.search(query)) ).subscribe(results => { this.displayResults(results); }); } search(query: string): Observable<SearchResult[]> { return this.http.get<SearchResult[]>(`/api/search?q=${query}`); } displayResults(results: SearchResult[]) { // 显示搜索结果 }}3. 路由处理使用 RxJS 处理路由参数和查询参数。import { Component, OnInit } from '@angular/core';import { ActivatedRoute, Router } from '@angular/router';@Component({ selector: 'app-user-detail', template: ` <div *ngIf="user$ | async as user"> <h1>{{ user.name }}</h1> <p>{{ user.email }}</p> </div> `})export class UserDetailComponent implements OnInit { user$: Observable<User>; constructor( private route: ActivatedRoute, private router: Router, private dataService: DataService ) {} ngOnInit() { // 监听路由参数变化 this.user$ = this.route.paramMap.pipe( switchMap(params => { const id = Number(params.get('id')); return this.dataService.getUserById(id); }) ); } navigateToUser(id: number) { this.router.navigate(['/users', id]); }}4. 状态管理使用 BehaviorSubject 或 NgRx 进行状态管理。简单状态管理:import { Injectable } from '@angular/core';import { BehaviorSubject, Observable } from 'rxjs';@Injectable({ providedIn: 'root'})export class StateService { private state$ = new BehaviorSubject<AppState>({ user: null, isLoading: false, error: null }); getState(): Observable<AppState> { return this.state$.asObservable(); } updateUser(user: User) { const currentState = this.state$.value; this.state$.next({ ...currentState, user }); } setLoading(loading: boolean) { const currentState = this.state$.value; this.state$.next({ ...currentState, isLoading: loading }); }}在组件中使用:@Component({ selector: 'app-app', template: ` <div *ngIf="state$ | async as state"> <div *ngIf="state.isLoading">Loading...</div> <div *ngIf="state.user">Welcome, {{ state.user.name }}</div> </div> `})export class AppComponent { state$: Observable<AppState>; constructor(private stateService: StateService) { this.state$ = this.stateService.getState(); }}高级应用模式1. 使用 AsyncPipeAsyncPipe 自动管理订阅和取消订阅。@Component({ selector: 'app-user-list', template: ` <div *ngIf="users$ | async as users"> <div *ngFor="let user of users"> {{ user.name }} </div> </div> `})export class UserListComponent { users$: Observable<User[]>; constructor(private dataService: DataService) { this.users$ = this.dataService.getUsers(); }}2. 使用 takeUntil 防止内存泄漏import { Component, OnInit, OnDestroy } from '@angular/core';import { Subject } from 'rxjs';import { takeUntil } from 'rxjs/operators';@Component({ selector: 'app-component', template: `...`})export class MyComponent implements OnInit, OnDestroy { private destroy$ = new Subject<void>(); ngOnInit() { this.dataService.getUsers().pipe( takeUntil(this.destroy$) ).subscribe(users => { this.users = users; }); } ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); }}3. 使用 shareReplay 缓存数据import { Injectable } from '@angular/core';import { Observable, shareReplay } from 'rxjs';@Injectable({ providedIn: 'root'})export class CacheService { private cache = new Map<string, Observable<any>>(); get<T>(key: string, fetchFn: () => Observable<T>): Observable<T> { if (!this.cache.has(key)) { this.cache.set(key, fetchFn().pipe( shareReplay(1) )); } return this.cache.get(key) as Observable<T>; } clear() { this.cache.clear(); }}4. 使用 combineLatest 组合多个数据源@Component({ selector: 'app-dashboard', template: ` <div *ngIf="dashboardData$ | async as data"> <h2>Users: {{ data.users.length }}</h2> <h2>Posts: {{ data.posts.length }}</h2> <h2>Comments: {{ data.comments.length }}</h2> </div> `})export class DashboardComponent { dashboardData$: Observable<DashboardData>; constructor(private dataService: DataService) { this.dashboardData$ = combineLatest([ this.dataService.getUsers(), this.dataService.getPosts(), this.dataService.getComments() ]).pipe( map(([users, posts, comments]) => ({ users, posts, comments })) ); }}常见问题和解决方案1. 处理错误this.dataService.getUsers().pipe( catchError(error => { console.error('Failed to load users:', error); return of([]); // 返回空数组作为降级 })).subscribe(users => { this.users = users;});2. 重试失败的请求this.dataService.getUsers().pipe( retry(3), // 重试 3 次 catchError(error => { console.error('Failed after retries:', error); return of([]); })).subscribe(users => { this.users = users;});3. 加载状态管理@Component({ selector: 'app-user-list', template: ` <div *ngIf="isLoading">Loading...</div> <div *ngIf="users$ | async as users"> <div *ngFor="let user of users"> {{ user.name }} </div> </div> `})export class UserListComponent { isLoading = false; users$: Observable<User[]>; constructor(private dataService: DataService) {} loadUsers() { this.isLoading = true; this.dataService.getUsers().pipe( finalize(() => { this.isLoading = false; }) ).subscribe(users => { this.users = users; }); }}4. 搜索防抖@Component({ selector: 'app-search', template: ` <input #searchInput (input)="onSearch($event)" placeholder="Search..."> <div *ngIf="results$ | async as results"> <div *ngFor="let result of results"> {{ result.name }} </div> </div> `})export class SearchComponent { results$: Observable<SearchResult[]>; constructor(private dataService: DataService) {} onSearch(event: Event) { const query = (event.target as HTMLInputElement).value; this.results$ = of(query).pipe( debounceTime(300), distinctUntilChanged(), switchMap(q => this.dataService.search(q)) ); }}最佳实践1. 使用 AsyncPipe// ✅ 推荐@Component({ template: `<div *ngIf="data$ | async as data">{{ data }}</div>`})export class MyComponent { data$ = this.service.getData();}// ❌ 不推荐@Component({ template: `<div>{{ data }}</div>`})export class MyComponent implements OnInit, OnDestroy { data: any; private subscription: Subscription; ngOnInit() { this.subscription = this.service.getData().subscribe(data => { this.data = data; }); } ngOnDestroy() { this.subscription.unsubscribe(); }}2. 防止内存泄漏// ✅ 推荐export class MyComponent implements OnDestroy { private destroy$ = new Subject<void>(); ngOnInit() { this.service.getData().pipe( takeUntil(this.destroy$) ).subscribe(data => { this.data = data; }); } ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); }}// ❌ 不推荐export class MyComponent { ngOnInit() { this.service.getData().subscribe(data => { this.data = data; }); // 忘记取消订阅 }}3. 错误处理// ✅ 推荐this.service.getData().pipe( catchError(error => { console.error('Error:', error); return of(defaultData); })).subscribe(data => { this.data = data;});// ❌ 不推荐this.service.getData().subscribe({ next: data => { this.data = data; }, error: error => { console.error('Error:', error); // 没有降级处理 }});4. 类型安全// ✅ 推荐interface User { id: number; name: string; email: string;}this.http.get<User[]>('/api/users').subscribe(users => { users.forEach(user => { console.log(user.name); // 类型安全 });});// ❌ 不推荐this.http.get('/api/users').subscribe((users: any) => { users.forEach((user: any) => { console.log(user.name); // 没有类型检查 });});总结RxJS 在 Angular 中的关键应用:HTTP 请求: 使用 HttpClient 处理异步请求表单处理: 监听表单值变化,实现防抖和验证路由处理: 监听路由参数和查询参数变化状态管理: 使用 BehaviorSubject 或 NgRx 管理应用状态AsyncPipe: 自动管理订阅,防止内存泄漏错误处理: 使用 catchError 和 retry 处理错误性能优化: 使用 debounceTime、shareReplay 等优化性能掌握 RxJS 在 Angular 中的应用是成为 Angular 高级开发者的关键。
阅读 0·2月21日 16:54