一、简介
HTTP OPTIONS请求用于描述目标资源的通信选项,主要用途有:
1、CORS(跨来源资源共享) 预检请求。
在CORS场景中,当客户端尝试使用非简单请求(如PUT、DELETE、带有自定义头的POST请求等)访问跨域资源时,浏览器会首先发送一个OPTIONS请求到服务器,以检查服务器是否允许该跨域请求(如:当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段)。
服务器在收到OPTIONS请求后,会返回一个包含CORS相关响应头的响应,告知客户端是否允许该跨域请求。
补充1:
(1)简单请求:
a、请求方法是以下三种方法之一:
- HEAD
- GET
- POST
b 、HTTP的头信息不超出以下几种字段:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
(2)非简单请求
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的 类型是application/json。
补充2:
对于每个非简单请求,浏览器都会发送一个预检请求。但是,如果浏览器已经知道服务器的CORS策略(例如,通过之前的简单请求获得),并且这个策略对于当前的非简单请求是有效的,那么浏览器就不需要再次发送预检请求。
预检请求结果会缓存。
会返回204。响应的报文中不含实体主体。
2、网络调试。
开发人员可以使用OPTIONS请求来测试服务器对特定资源的支持情况,以及获取有关服务器配置和能力的信息。
二、背景和问题
1、背景
在服务器等保三级审核时间有限的背景下,为满足客户对平台服务器的等保要求,使用了一个已经审核通过的服务器用nginx做了反向代理。
2、问题
微信公众号软件无法绑定用户,请求接口一直报错,但通过postman访问接口却可以成功。
三、环境搭建及问题解决
1、 找服务器安装一个nginx,在服务器开放端口
2、 配置反向代理
server {
listen 9998;
server_name localhost;
#add_header 'Access-Control-Allow-Origin' '*';
#add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
location /amiwatergas113/ {
# add_header 'Access-Control-Allow-Origin' '*'; # 或具体源地址
# add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
# add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,lang';
proxy_pass https://xxxxxxx.com/api/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
}
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
3、 问题复现
(1)options请求 缺少请求属性 CORS Missing Allow Origin
搭建完环境,配置完反向代理直接运行nginx,通过前端代码访问中间服务器的代理地址。
结果:
image.png
(2)options请求 Access-Control-Allow-Headers 缺失
我们把Access-Control-Allow-Origin
属性加上,重启nginx,并前端请求
结果:
(3)post请求头信息重复配置,但options请求通过了
此时,我们把所有的跨域请求的nginx配置加上。重启nginx。
结果:预检请求通过了,但post请求提示请求信息重复配置
(4)options请求 缺少请求属性 CORS Missing Allow Origin
所以我们把这个 多的请求信息注释掉
重启nginx运行后,请求发现又回到了第一种情况
(5)最终版
当时卡在这个地方很久,现在回头来看,就是options请求缺失了Access-Control-Allow-Origin
配置,
而 post请求并不需要这个配置。所以加一个判断就可以了。
结果:
接口请求成功
Nginx 的配置中,if 语句可以用来根据条件执行不同的配置块,但是 它的 if 语句的行为与其他编程语言或脚本语言中的 if-else 有所不同,它不直接支持 else 子句,是通过在 if 语句外部定义其他配置来隐式地实现“否则”的逻辑。
四、其他
补充1:location和proxy_pass
(1) proxy_pass后的URL 无 /
location /xxx {
proxy_pass http://backend.example.com;
# 其他指令...
}
- 没有尾部斜杠:如果 proxy_pass 后面的 URL 没有尾部斜杠,并且请求的 URI 包含尾部斜杠(如 /xxx/),则 Nginx 会将请求转发到 http://backend.example.com/xxx/(即保留原始 URI)。如果请求的 URI 没有尾部斜杠(如 /xxx),Nginx 会将其转发为 http://backend.example.com/xxx(去除 Nginx 中的 URI 末尾的斜杠,如果存在的话)。
- 有尾部斜杠:如果 proxy_pass 后面的 URL 包含尾部斜杠(如 http://backend.example.com/),则 Nginx 会将请求 URI 中与 location 指令匹配的部分替换为空字符串(即去除这部分 URI),并将剩余的 URI 部分附加到 proxy_pass 指定的 URL 后面。