在 Ubuntu 服务器上执行以下命令:
bash展开代码# 安装必要的包
sudo apt update
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
# 添加 Caddy 官方 GPG 密钥
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
# 添加 Caddy 仓库
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
# 安装 Caddy
sudo apt update
sudo apt install caddy
bash展开代码# 停止默认的 Caddy 服务
sudo systemctl stop caddy
# 创建配置目录
sudo mkdir -p /etc/caddy
# 将 Caddyfile 上传到服务器
# 将我创建的 Caddyfile 内容复制到 /etc/caddy/Caddyfile
sudo nano /etc/caddy/Caddyfile
将上面生成的 Caddyfile
内容复制到这个文件中。
Caddyfile如下:
专门处理 CORS 预检请求 (OPTIONS 方法),设置允许的跨域请求头和方法,Access-Control-Max-Age 1728000 (20天) 表示预检请求的缓存时间,直接返回 204 空响应,符合预检请求规范。
json展开代码# 通用端口转发配置模板
:8055, :8056, :8057, :8058, :8059, :8060, :8061, :8062, :8063, :8064, :8065, :8066, :8067, :8068, :8069, :8070 {
# 处理 OPTIONS 预检请求
@options method OPTIONS
header @options {
Access-Control-Allow-Origin *
Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE"
Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization"
Access-Control-Max-Age 1728000
}
respond @options 204
reverse_proxy 10.150.72.28:{http.request.port}
header {
Access-Control-Allow-Origin *
Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE"
Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization"
Access-Control-Expose-Headers "Content-Length,Content-Range"
}
}
bash展开代码# 验证配置文件语法
sudo caddy validate --config /etc/caddy/Caddyfile
# 启动 Caddy
sudo systemctl start caddy
# 设置开机自启
sudo systemctl enable caddy
# 查看状态
sudo systemctl status caddy
# 查看日志
sudo journalctl -u caddy -f
bash展开代码# 停止 nginx(避免端口冲突)
sudo systemctl stop nginx
sudo systemctl disable nginx
写好 docker-compose.yaml , 然后 docker compose up -d
:
yaml展开代码version: '3'
# 定义自定义网络
networks:
vanblog-network:
driver: bridge
services:
caddy-proxy:
image: caddy:latest
restart: always
ports:
- "8055-8070:8055-8070"
volumes:
- ${PWD}/caddy-proxy/Caddyfile:/etc/caddy/Caddyfile
- ${PWD}/caddy-proxy/data:/data
- ${PWD}/caddy-proxy/config:/config
networks:
- vanblog-network
environment:
TZ: 'Asia/Shanghai'
bash展开代码# 重新加载配置(无停机)
sudo caddy reload --config /etc/caddy/Caddyfile
# 格式化配置文件
caddy fmt /etc/caddy/Caddyfile --overwrite
# 查看配置
caddy list-modules
CORS(Cross-Origin Resource Sharing,跨源资源共享) 是一种浏览器安全机制,用于控制不同源(Origin)之间的资源访问。
https://example.com
)请求后端 API(如 https://api.example.com
),由于域名不同,浏览器会阻止请求,除非后端明确允许跨域访问。CORS 预检请求(Preflight Request) 是浏览器在发送某些**非简单请求(Non-Simple Request)**之前,先发送一个 OPTIONS
请求,询问服务器是否允许该跨域请求。
浏览器在以下情况会先发送 OPTIONS
请求(预检请求):
PUT
、DELETE
、PATCH
等)。Authorization
、X-Custom-Header
)。Content-Type
不是 application/x-www-form-urlencoded
、multipart/form-data
或 text/plain
(如 application/json
)。浏览器发送 OPTIONS
请求,包含:
Access-Control-Request-Method
:要使用的 HTTP 方法(如 PUT
)。Access-Control-Request-Headers
:自定义请求头(如 Authorization
)。Origin
:请求来源(如 https://example.com
)。服务器响应 OPTIONS
请求,返回:
Access-Control-Allow-Origin
:允许的源(如 *
或 https://example.com
)。Access-Control-Allow-Methods
:允许的方法(如 GET, POST, PUT, DELETE
)。Access-Control-Allow-Headers
:允许的请求头(如 Authorization
)。Access-Control-Max-Age
:预检请求的缓存时间(如 1728000
秒)。如果服务器允许,浏览器才会发送真正的请求(如 PUT /data
)。
类型 | 简单请求(Simple Request) | 非简单请求(Non-Simple Request) |
---|---|---|
HTTP 方法 | GET 、POST 、HEAD | PUT 、DELETE 、PATCH 等 |
请求头 | 仅允许标准头(如 Accept 、Content-Type 等) | 包含自定义头(如 Authorization ) |
Content-Type | text/plain 、application/x-www-form-urlencoded 、multipart/form-data | application/json 等 |
是否需要预检请求 | ❌ 不需要 | ✅ 需要 |
HTTP 头 | 作用 |
---|---|
Access-Control-Allow-Origin | 允许访问的源(如 * 或 https://example.com ) |
Access-Control-Allow-Methods | 允许的 HTTP 方法(如 GET, POST, PUT, DELETE ) |
Access-Control-Allow-Headers | 允许的请求头(如 Authorization, Content-Type ) |
Access-Control-Expose-Headers | 允许前端访问的响应头(如 Content-Length ) |
Access-Control-Max-Age | 预检请求的缓存时间(如 1728000 秒) |
Access-Control-Allow-Credentials | 是否允许携带 Cookie(如 true ) |
http展开代码GET /data HTTP/1.1 Host: api.example.com Origin: https://example.com
服务器响应:
http展开代码HTTP/1.1 200 OK Access-Control-Allow-Origin: * Content-Type: application/json {"data": "Hello, CORS!"}
预检请求(OPTIONS):
http展开代码OPTIONS /data HTTP/1.1 Host: api.example.com Origin: https://example.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: Authorization
服务器响应:
http展开代码HTTP/1.1 204 No Content Access-Control-Allow-Origin: https://example.com Access-Control-Allow-Methods: PUT Access-Control-Allow-Headers: Authorization Access-Control-Max-Age: 1728000
真正的请求(PUT):
http展开代码PUT /data HTTP/1.1 Host: api.example.com Origin: https://example.com Authorization: Bearer token123 Content-Type: application/json {"name": "John"}
本文作者:Dong
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC。本作品采用《知识共享署名-非商业性使用 4.0 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!