ASP.NET Core WebAPI 前后端分离中跨域问题解决方法

本文阅读 4 分钟
首页 信息技术 正文

最近一段时间,我一直在积极尝试对站点的后台管理系统进行重大的架构调整,即将其前后端分离,并且把后台改造为 asp.net core webapi 的形式。在这个充满挑战的过程中,我着实遇到了其中的一些棘手问题。
首先需要明确的是,在进行前后端分离后,跨域问题必然会成为一个需要重点关注和解决的关键环节。虽然可以通过使用代理的方式来实现跨域访问,但考虑到代码是由自己掌控的,完全可以进行针对性的修改和优化,以达到更好的效果。
在 asp.net core 中,要解决跨域问题,首先需要在 Startup.cs 文件的 ConfigureServices 方法中添加以下代码:
services.AddCors(options =>
{

options.AddPolicy("any", builder =>
{
    builder.AllowAnyOrigin() //允许任何来源的主机访问
    //builder.WithOrigins("http://localhost:8080") //允许特定的 http://localhost:8080 的主机访问
   .AllowAnyMethod()
   .AllowAnyHeader()
   .AllowCredentials();//指定处理 cookie
});

});
接着,在下面的 Configure 方法中加入 app.UseCors("any");。原本以为这样就能够顺利解决跨域问题,然而实际情况却并非如此,依旧出现了报错信息。
为了解决这个问题,我决定加入一个过滤器,用于在请求的 Header 中手动添加 Access-Control-Allow-Origin 等关键信息。以下是过滤器的具体实现代码:
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Blogs.Service.Manage
{

public class CorsActionFilter : IActionFilter
{
    public void OnActionExecuted(ActionExecutedContext context)
    {

    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        string referer = context.HttpContext.Request.Headers["Referer"].ToString();
        if (!String.IsNullOrEmpty(referer))
        {
            context.HttpContext.Response.Headers.Add("Access-Control-Allow-Origin", Regex.Match(referer, "(https{0,1}://.*?)/").Groups[1].Value);
            context.HttpContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true");   //这个为 true 时,Access-Control-Allow-Origin 不能设置为 *
            context.HttpContext.Response.Headers.Add("Access-Control-Allow-Methods", "*");  //GET, HEAD, OPTIONS, POST, PUT
            context.HttpContext.Response.Headers.Add("Access-Control-Allow-Headers", "*");  //Access-Control-Allow-Headers, Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers
        }
        else
        {
            context.HttpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
            context.HttpContext.Response.Headers.Add("Access-Control-Allow-Methods", "*");
            context.HttpContext.Response.Headers.Add("Access-Control-Allow-Headers", "*");
        }
    }
}

}
然后,在 Startup 中的 ConfigureServices 方法中再次添加以下代码:
csharp
Copy
services.AddMvc(config =>
{

config.Filters.Add(new CorsActionFilter());

});
需要特别注意的是,当 Access-Control-Allow-Credentials 设置为 true 的时候,Access-Control-Allow-Origin 不能为 *。在此之前,我自己也并不清楚这个关键要点。Credentials 的主要作用在于,当使用 JavaScript 进行请求的时候能够带上 Cookie,这样服务端就可以准确识别请求的来源。例如在使用 axios 库时,可以设置 axios.defaults.withCredentials=true;。
貌似如果不进行第一步,只进行第二步,在使用 Get 方法的时候可能不会出现问题,但在进行 POST 请求时很可能会不成功。
在这个过程中,我还遇到过返回 401 状态码的情况,甚至连方法体都无法进入。
我发现在进行 POST 请求的时候,会先有一个 Options 请求,但这个请求却会报 404 错误。于是,我在方法上加上了 [HttpOptions] 特性,然而偶然间发现这样会导致方法被执行两次,并且实体参数无法获取到值。后来,我在 Controller 上加上 ApiController 特性,再去掉 HttpOptions,才最终成功解决了这个问题。需要强调的是,上面所说的内容可能并不全面,具体的情况可以一个一个进行尝试……
此外,我还遇到了一个问题,那就是我发现当在 Session 中存储了值后,下次却无法获取到这个值。经过在网上查询,发现需要去掉 Startup 中 ConfigureServices 方法的这段代码:
services.Configure(options =>
{

options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;

});
在此,我将这些问题和解决方法记录下来,以便日后遇到类似情况时可以快速参考和解决。

本文来自投稿,不代表本站立场,如若转载,请注明出处:
张学良百岁养生秘笈!下面这五点很重要
« 上一篇 11-02
解决项目引用本地局域网 Nuget 服务器
下一篇 » 11-05