Safari 无法通过 CORS
本文关键字:CORS Safari | 更新日期: 2023-09-27 18:34:02
我正在使用DynamicPolicyProviderFactory来确定在 Asp.Net Web API 2.2应用程序中是否允许来自域的请求。 为了做出这个决定,我使用了Web.Config中定义的几个正则表达式模式
。 <applicationSettings>
<MyApp.Properties.Settings>
<setting name="AllowedDomains" serializeAs="Xml">
<value>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>http://localhost</string>
<string>http*://*.domain1.com</string>
<string>http*://*.domain2.com</string>
</ArrayOfString>
</value>
</setting>
</MyApp.Properties.Settings>
</applicationSettings>
然后在我的DynamicPolicyProviderFactory
中,我创建了一个可以使用的正则表达式:
//constructor
public DynamicPolicyProviderFactory(IEnumerable allowedOrigins)//allowedDrigins is the strings passed from the config {
_allowed = new HashSet<Regex>();
foreach (string pattern in allowedOrigins.Cast<string>()
.Select(Regex.Escape)
.Select(pattern => pattern.Replace("*", "w*")))
{
_allowed.Add(new Regex(pattern, RegexOptions.IgnoreCase));
}
if (_allowed.Count > 0)
return;
//if nothing is specified, we assume everything is.
_allowed.Add(new Regex(@"https://'w*", RegexOptions.IgnoreCase));
_allowed.Add(new Regex(@"http://'w*", RegexOptions.IgnoreCase));
}
public ICorsPolicyProvider GetCorsPolicyProvider(HttpRequestMessage request)
{
var route = request.GetRouteData();
var controller = (string)route.Values["controller"];
var corsRequestContext = request.GetCorsRequestContext();
var originRequested = corsRequestContext.Origin;
var policy = GetPolicyForControllerAndOrigin(controller, originRequested);
return new CustomPolicyProvider(policy);
}
//this is where the magic happens
private CorsPolicy GetPolicyForControllerAndOrigin(string controller, string originRequested)
{
// Do lookup to determine if the controller is allowed for
// the origin and create CorsPolicy if it is (otherwise return null)
if (_allowed.All(a => !a.Match(originRequested).Success))
return null;
var policy = new CorsPolicy();
policy.Headers.Add("accept");
policy.Headers.Add("content-type");
policy.Origins.Add(originRequested);
policy.Methods.Add("GET");
policy.Methods.Add("POST");
policy.Methods.Add("PUT");
policy.Methods.Add("DELETE");
policy.Methods.Add("OPTIONS");
return policy;
}
假设请求来源为:http://sub.domain1.com,脚本位置为 http://sub.domain1.com:8080。 这在Chrome,IE,FireFox和Opera中完美运行,但在Safari中失败。 奇怪的是,Safari在浏览器控制台中给出的错误是
Failed to load resource: Origin http://sub.domain1.com is not allowed by Access-Control-Allow-Origin
可能会发生什么?
我观察到的另一个奇怪之处是,如果我的源和脚本位置都是 http:sub.domain1.com:8080,则 CORS 请求是由 Safari 发出的(并通过(,但其他浏览器正确地将其视为同一来源。
编辑:我发现如果我在GetPolicyForControllerAndOrigin
返回 null 的地方放置一个断点,它永远不会命中,并且会正确创建并返回策略。
编辑 2:我检查了服务器对 Safari 的 OPTIONS 请求的响应,发现响应中缺少标头Access-Control-Allow-Headers
和Access-Control-Allow-Origin
标头。此外,在请求端,Safari 没有添加 Host
标头。 这是必需的吗? 这就是它失败的原因吗?
问题出在 Safari 的 OPTIONS 请求上。 我只允许accept
和content-type
允许的标头,但 Safari 也要求origin
。