之前写了有关跨域访问的几篇文章:
回顾重点: Origin=schema+ Host+ Port,
不同源的浏览器脚本(javascript、ActionScript、canvas)在没明确授权的情况下,不能读写对方的资源。
CORS是W3C推出的跨域请求方案: 让web服务器明确授权非同源页面脚本来访问自己, 以Response特定响应头Access-Control-- 体现; 目前现代浏览器均认可并支持这些标头。
浏览器跨域访问时, 会自动带上Origin请求头。
当出现非简单请求, 浏览器会自动产生预检Options请求,使用Access-Control-Request-Method、Access-Control-Request-Headers和Origin请求头, 先去web服务器确认跨域访问时允许的方法和自定义请求头。
如果预检Options请求未能通过,后续的实际请求将不会发起。

这里提示一个重要的编程实践:

1> 脚本默认不携带凭据 2> 脚本可通过WithCredentials= true 配置要求浏览器携带凭据。
有一个例外预检Options始终不会携带凭据[3],但在常见的web编程实践中(凭据认证会在处理管道的前面),如果预检Options返回非200, 后续的实际请求就不会发起, 所以请考虑对预检Options请求忽略凭据访问。
kong网关的CORS的插件,配置Preflight Continue可以帮助规避这个编程实践问题。

默认preflight_continue = false, 意味着插件不将预检请求转发给upstream,所以此处保持默认就好, 网关会根据请求特征和CORS配置产生CORS响应头,并返回你期待的200 OK响应码。
function CorsHandler:access(conf)
local req_origin = kong.request.get_header("Origin")
if kong.request.get_method() ~= "OPTIONS"
or not is_origin_provided(req_origin)
or not kong.request.get_header("Access-Control-Request-Method")
then
return
end
-- don't add any response header because we are delegating the preflight to
-- the upstream API (conf.preflight_continue=true), or because we already
-- added them all
kong.ctx.plugin.skip_response_headers = true
if conf.preflight_continue then
return
end
//......
return kong.response.exit(HTTP_OK)
end
源码在https://github.com/Kong/kong/blob/255d4a1fad88082c13a875fdf1a70ceb4e4ea457/kong/plugins/cors/handler.lua#L210
如果你手痒设置成true,那么预检请求就会转发到upstream,需要后端自己去忽略对预检Options请求的凭据认证。
参考资料
[1]
全网最全的跨域资源共享CORS方案分析: https://www.cnblogs.com/JulianHuang/p/10337980.html
[2]
CORS预检Options请求的思考: https://www.cnblogs.com/JulianHuang/p/14225515.html
[3]
预检Options始终不会携带凭据: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Allow-Credentials

本文和配图均为原创,搁笔常恐意味尽,愿闻读者金玉声。