解决办法是通过在 Nginx 中把对 /static/
路径的请求直接指向你的 COS 域名来实现让浏览器直接去拉取 COS 上的静态资源,而不再经过本地服务器。下面给出两种常见的做法,你可以任选其一:
方法一:使用 301/302 Redirect (让客户端直接跳转到 COS)
这样做的好处是浏览器会直接到 COS 域名去请求资源,减少了你这边服务器的流量和延迟。配置思路就是把所有 /static/...
的请求都重写(rewrite)到 COS 的真实 URL 上去。
nginx
server {
listen 80;
server_name 62.234.180.150;
# 其他配置...
# 这一段把 /static/ 下的所有请求都重定向到你 COS 上的静态目录
location ^~ /static/ {
# 正则捕获 /static/ 后面的部分(比如 chat/images/gongan.png)
rewrite ^/static/(.*)$ https://pygrow-1307692287.cos.ap-chongqing.myqcloud.com/staticfiles/$1 redirect;
# 如果想要永久 301,可以改成:
# rewrite ^/static/(.*)$ https://pygrow-1307692287.cos.ap-chongqing.myqcloud.com/staticfiles/$1 permanent;
}
# 媒体文件(media)也可以同理
location ^~ /media/ {
rewrite ^/media/(.*)$ https://pygrow-1307692287.cos.ap-chongqing.myqcloud.com/media/$1 redirect;
}
# 主代理配置:其余请求转发到 Django
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $http_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;
# WebSocket 支持(可选,看你是否用到 channels/ws)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
proxy_connect_timeout 30s;
proxy_buffering off;
}
# ...其他配置
}
-
解释
-
location ^~ /static/ { ... }
:匹配所有以/static/
打头的请求。 -
rewrite ^/static/(.*)$ https://pygrow-1307692287.cos.ap-chongqing.myqcloud.com/staticfiles/$1 redirect;
^/static/(.*)$
捕获/static/
后面的所有路径(比如chat/images/gongan.png
)。- 将其一一映射到
https://pygrow-1307692287.cos.ap-chongqing.myqcloud.com/staticfiles/$1
,也就是 COS 上对应的路径。 redirect
表示返回 302 临时重定向;如果你希望客户端缓存(301 永久重定向),就把redirect
改成permanent
即可。
-
浏览器拿到 302/301 后就直接去请求 COS 上的 URL,从而节省了你本地服务器转发这一步骤,也能显著提升静态文件加载速度。
-
注意 :采用此方案后,你需要保持 Django 端的
STATIC_URL = '/static/'
不变,让模板输出的 URL 依旧是/static/...
。Nginx 收到客户端对/static/...
的请求,就会自动下发 301/302 给浏览器,让它去 COS 拉资源。
方法二:使用 proxy_pass (由 Nginx 反向代理到 COS,浏览器只请求你这台服务器)
如果你希望浏览器在地址栏里仍然是 https://你的域名/static/...
,但实际内容由 Nginx 从 COS "取回"后再转给客户端,也可以用 proxy_pass
。这种方式浏览器 "看" 不到真正的 COS 域名,所有流量还是走到你这台 Nginx,然后再到 COS。
nginx
server {
listen 80;
server_name 62.234.180.150;
# 其他配置...
# 代理 /static/ 到 COS
location /static/ {
# 下面这个 proxy_pass 的写法,能够把 /static/foo/bar.js
# 对应到 https://pygrow-1307692287.cos.ap-chongqing.myqcloud.com/staticfiles/foo/bar.js
proxy_pass https://pygrow-1307692287.cos.ap-chongqing.myqcloud.com/staticfiles/;
# 一般还要设置 Host,指向你 COS 的域名
proxy_set_header Host pygrow-1307692287.cos.ap-chongqing.myqcloud.com;
# 缓存头、CORS 等可酌情加
expires 30d;
add_header Cache-Control "public, max-age=2592000";
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, OPTIONS';
# 如果需要 WebSocket 支持,通常不用在 static 里设置
proxy_http_version 1.1;
}
# 媒体文件 同理
location /media/ {
proxy_pass https://pygrow-1307692287.cos.ap-chongqing.myqcloud.com/media/;
proxy_set_header Host pygrow-1307692287.cos.ap-chongqing.myqcloud.com;
expires 30d;
add_header Cache-Control "public, max-age=2592000";
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, OPTIONS';
proxy_http_version 1.1;
}
# 主代理,把其他请求转给 Django
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $http_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;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
proxy_connect_timeout 30s;
proxy_buffering off;
}
# ...其他配置
}
-
解释
-
location /static/
:匹配到的请求仍然是以/static/
打头。 -
proxy_pass https://pygrow-1307692287.cos.ap-chongqing.myqcloud.com/staticfiles/;
-
注意最后要保留一个斜杠,这样 Nginx 会把
/static/
后面的部分拼接到/staticfiles/
后面,举例:- 客户端请求
/static/chat/images/gongan.png
- Nginx 会把它转发给
https://pygrow-1307692287.cos.ap-chongqing.myqcloud.com/staticfiles/chat/images/gongan.png
- 客户端请求
-
-
proxy_set_header Host pygrow-1307692287.cos.ap-chongqing.myqcloud.com;
- 让 Nginx 在向 COS 发起请求时,
Host
头是你 COS 的桶域名,否则 COS 可能会拒绝访问或者返回 404。
- 让 Nginx 在向 COS 发起请求时,
-
其余的
expires
、Cache-Control
、Access-Control-Allow-Origin
都是为了强制客户端缓存、并允许跨域请求。
-
小结与建议
-
如果你希望"浏览器直接去 COS 拉",减轻自己服务器负担,就用方法一(Redirect)。
- 优点:浏览器绕过你这台机器,直接和 COS 通信,节省带宽和 CPU。
- 缺点:URL 从
/static/...
变成了https://pygrow-1307692287.cos.ap-chongqing.myqcloud.com/staticfiles/...
,地址栏里会发生跳转。
-
如果你希望"URL 看起来还是
/static/...
,但是背后 Nginx 去取 COS 的内容",用方法二(proxy_pass)。- 优点:URL 对用户而言是一致的,也方便做统一日志/安全策略;对客户端透明。
- 缺点:所有静态请求都要经过你这台服务器一次,带宽依然会消耗在你服务器和 COS 之间。
-
不要忘了同步修改 Django 侧:
-
保持
settings.py
里的pythonSTATIC_URL = '/static/'
如果你改成
STATIC_URL = 'https://pygrow-1307692287.cos.ap-chongqing.myqcloud.com/staticfiles/'
,那么 Django 直接在模板里就会生成完整的 COS 链接,此时 Nginx 不再需要额外的/static/
转发配置------静态文件就完全由 COS 托管,但这样做的前提是你希望模板层直接暴露外网 Bucket 地址。
-
-
部署完成后,记得清理(或者暂时关闭)本地的静态文件服务,否则可能会跟 Nginx 的代理/重写冲突。也可以在 Nginx 里把原来指向本地
alias
或root
的部分删掉,只保留重写/代理到 COS 的配置。
配置示例(最终版)
假设你想要使用"让浏览器直接跳到 COS"方案,最终的 Nginx 段落可以像下面这样:
nginx
server {
listen 80;
server_name 62.234.180.150;
# 1. 静态文件直接重定向到 COS
location ^~ /static/ {
rewrite ^/static/(.*)$ https://pygrow-1307692287.cos.ap-chongqing.myqcloud.com/staticfiles/$1 permanent;
}
# 2. 媒体文件(Media)同理
location ^~ /media/ {
rewrite ^/media/(.*)$ https://pygrow-1307692287.cos.ap-chongqing.myqcloud.com/media/$1 permanent;
}
# 3. 其余请求都转给 Django
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $http_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;
# WebSocket(如果用到 channels)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
proxy_connect_timeout 30s;
proxy_buffering off;
}
# 日志等配置...
access_log /www/wwwlogs/www_pygrow_cn.log;
error_log /www/wwwlogs/www_pygrow_cn.error.log;
}
这样一来:
- 用户在浏览器里访问
https://62.234.180.150/static/chat/images/gongan.png
- Nginx 立刻返回一个 301 到
https://pygrow-1307692287.cos.ap-chongqing.myqcloud.com/staticfiles/chat/images/gongan.png
- 浏览器直接去 COS 上拉取图片,速度最快,也不占你本机带宽。
如果你更倾向于"URL 保持没变,但代理走 COS",则把第 1、2 步改成前面示例的 proxy_pass
写法即可。
常见坑
- 不要同时存在两个
/static/
匹配,否则 Nginx 会优先走第一个匹配到的。 - 如果你用的是 HTTPS(在前端做了反代 SSL),请把
proxy_pass
换成https://...
并确认 SSL 证书链正确。 - 重定向到 COS 时,记得检查 COS 桶的权限(要保证对外是公开可读,否则会 403/404)。
- 如果你以后要让 COS 上的静态文件"版本化"或"带签名 URL",可以在 rewrite 里拼带签名的参数。
总结:
- 最推荐的做法是 方法一(Redirect)。这样静态资源完全脱离你当前服务器,浏览器去 COS 拉最快;
- 如果业务上有特殊需求一定要"URL 不改变",再考虑 方法二 (proxy_pass)。
按照上面示例修改好 Nginx,然后重载配置:
bash
nginx -t && nginx -s reload
就能让 Django 端的 /static/...
直接对接到你在 COS 上的资源了。