迁移问题
在ASP.NET 4.x时期,解决CORS问题是非常容易的,仅需在配置文件web.config里增加相应的配置节点即可,无法在程序中进行编码。在ASP.NET Core中,一切都是DI+配置Options化,确实有些不太习惯,也没有时间研究CORS配置化实现方法。所以只能把CORS配置项保存到appsettings.json文件里,然后在代码中编码实现CORS功能,因此,本文重点记录实现过程。
解决方案
1.ASP.NET 4.x时期web.config文件配置CORS
<system.webServer>
<httpProtocol>
<customHeaders>
<!--多个对象用英文逗号分隔-->
<add name="Access-Control-Allow-Origin" value="*" />
<!--若为true,Origin节点不能为*-->
<add name="Access-Control-Allow-Credentials" value="false" />
<!--多个对象用英文逗号分隔-->
<add name="Access-Control-Allow-Methods" value="GET,PUT,POST,DELETE,HEAD,OPTIONS" />
<!--多个对象用英文逗号分隔-->
<add name="Access-Control-Allow-Headers" value="X-Requested-With,origin,content-length,content-type,accept,Authorization,ApplicationType,LanguageType" />
<!--前端可以通过getResponseHeader读取值-->
<add name="Access-Control-Expose-Headers" value="Set-Token" />
<!--用来指定本次预检请求的有效期(20天),单位为秒,设置后有效期内不在发预检查请求-->
<add name="Access-Control-Max-Age" value="2592000" />
</customHeaders>
</httpProtocol>
</system.webServer>
2.ASP.NET Core的玩法
1)在appsettings.json文件里配置好CORS项
{
//配置CORS策略
"CorsPolicy": {
//多个对象用英文逗号分隔
"AllowOrigins": "*",
//若为true,Origin节点不能为*
"AllowCredentials": "false",
//多个对象用英文逗号分隔
"AllowMethods": "GET,PUT,POST,DELETE,HEAD,OPTIONS",
//多个对象用英文逗号分隔
"AllowHeaders": "X-Requested-With,origin,content-length,content-type,accept,Authorization,ApplicationType,LanguageType",
//前端可以通过getResponseHeader读取值
"ExposeHeaders": "Set-Token", //用来指定本次预检请求的有效期(20天),单位为秒,设置后有效期内不在发预检查请求 "MaxAge": 8640000
}
}
2)定义CORS策略对应的Options类CorsPolicyOptions
public class CorsPolicyOptions
{
public string AllowOrigins { get; set; } = "*";
public bool AllowCredentials { get; set; } = false;
public string AllowMethods { get; set; } = "GET,PUT,POST,DELETE,HEAD,OPTIONS";
public string AllowHeaders { get; set; } = "X-Requested-With,origin,content-length,content-type,accept,Authorization";
public string ExposeHeaders { get; set; } = "Set-Token";
public int MaxAge { get; set; } = 8640000;
}
3)定义appsettings.json文件对应的AppSettings类文件,在AppSettings类的私有类里实现CORS策略的读取
public class AppSetting
{
private static object _objLocker = new object();
private static AppSetting _instance;
private AppSetting() { }
public static AppSetting Instance
{
get
{
if (_instance == null)
{
lock (_objLocker)
{
if (_instance == null)
{
_instance = new AppSetting();
AppSettingConfig.Load(_instance);
}
}
}
return _instance;
}
}
private class AppSettingConfig
{
private static AppSetting _appSetting;
public static void Load(AppSetting appSetting)
{
_appSetting = appSetting;
Compute();
ChangeToken.OnChange(() => ConfigObjectManager.Instance.AppSetting.GetReloadToken(), () => { Change(); });
}
private static void Compute()
{
_appSetting.CorsPolicy = ConfigObjectManager.Instance.AppSetting.GetSection(ConstFiles.AppSettings_CorsPolicy).Get<CorsPolicyOptions>();
}
private static void Change()
{
}
}
#region Object Propertries
public CorsPolicyOptions CorsPolicy { get; private set; }
#endregion
}
4)配置CORS
public static void Config(IServiceCollection services)
{
if (AppSetting.Instance.CorsPolicy != null)
{
services.AddCors(options =>
{
options.AddDefaultPolicy(bd =>
{
if ("*" == AppSetting.Instance.CorsPolicy.AllowOrigins)
{
bd.SetIsOriginAllowed(_ => true);
}
else
{
var _tmpArray = AppSetting.Instance.CorsPolicy.AllowOrigins.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
bd.WithOrigins(_tmpArray);
}
if (AppSetting.Instance.CorsPolicy.AllowCredentials)
{
bd.AllowCredentials();
}
else
{
bd.DisallowCredentials();
}
var _tmpMethods = AppSetting.Instance.CorsPolicy.AllowMethods.IsNotNullEmptyWhiteSpace() ? AppSetting.Instance.CorsPolicy.AllowMethods : "GET,PUT,POST,DELETE,HEAD,OPTIONS";
bd.WithMethods(_tmpMethods);
var _tmpHeaders = AppSetting.Instance.CorsPolicy.AllowHeaders.IsNotNullEmptyWhiteSpace() ? AppSetting.Instance.CorsPolicy.AllowHeaders : "X-Requested-With,origin,content-length,content-type,accept,Authorization,ApplicationType,LanguageType";
bd.WithHeaders(_tmpHeaders);
var _tmpExposedHeaders = AppSetting.Instance.CorsPolicy.ExposeHeaders.IsNotNullEmptyWhiteSpace() ? AppSetting.Instance.CorsPolicy.ExposeHeaders : "";
bd.WithExposedHeaders(_tmpExposedHeaders);
var _tmpMaxAge = AppSetting.Instance.CorsPolicy.MaxAge > 1440 ? AppSetting.Instance.CorsPolicy.MaxAge : 8640000;
bd.SetPreflightMaxAge(TimeSpan.FromSeconds(_tmpMaxAge));
});
});
}
}
5)启用CORS
public static void Start(IApplicationBuilder app)
{
if (AppSetting.Instance.CorsPolicy != null)
{
app.UseCors();
}
}
总结
CORS在ASP.NET Core中实现还是比较简单的,只是习惯了不把可以配置化实现的代码写死在代码中,所以才有了上述编码逻辑。在上述代码中,我比较满意巨硬提供把配置文件中的对象转换为类对象这个操作的,想起在ASP.NET 4.x项目中都是手动实现,特别说明:咋ASP.NET 4.x项目中使用的配置文件格式ini。
测试源码:https://gitee.com/kinbor/jks.core.test.corsandconfig