已被CORS策略阻止:对预检请求的响应未通过访问控制检查。

125

我创建了旅游服务器。它正常工作,我们能够使用Insomnia进行POST请求,但是当我们在前端使用axios进行POST请求时,会发送错误:

has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: It does not have HTTP ok status.

我们对axios的请求:

let config = {
headers: {
  "Content-Type": "application/json",
  'Access-Control-Allow-Origin': '*',
  }
}

let data = {
  "id": 4
 }

 axios.post('http://196.121.147.69:9777/twirp/route.FRoute/GetLists', data, config)
   .then((res) => {
      console.log(res)
     })
    .catch((err) => {
      console.log(err)
   });
} 

我的go文件:

func setupResponse(w *http.ResponseWriter, req *http.Request) {
    (*w).Header().Set("Access-Control-Allow-Origin", "*")
    (*w).Header().Set("Access-Control-Allow-Methods", "POST,GET,OPTIONS, PUT, DELETE")

    (*w).Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
}


func WithUserAgent(base http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

    ctx := r.Context()
    ua := r.Header.Get("Jwt")
    ctx = context.WithValue(ctx, "jwt", ua)

    r = r.WithContext(ctx)

    setupResponse(&w, r)
     base.ServeHTTP(w, r)
  })
}

const (
    host     = "localhost"
    port     = 5432
    user     = "postgres"
    password = "postgres"
    dbname   = "postgres"
)

func main() {

    psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
           "password=%s dbname=%s sslmode=disable",
               host, port, user, password, dbname)

    server := &s.Server{psqlInfo}

    twirpHandler := p.NewFinanceServiceServer(server, nil)

    wrap := WithUserAgent(twirpHandler)
      log.Fatalln(http.ListenAndServe(":9707", wrap))
}

就像我之前在Insomnia中说过的,它非常好用。但是当我们使用axios进行POST请求时,在浏览器控制台中会出现以下内容:

已被CORS策略阻止:响应预检请求未通过访问控制检查:没有HTTP ok状态。


(*w).Header().Set("Access-Control-Allow-Origin", req.Header.Get("Origin")) - mkopriva
3
@mkopriva 不起作用。 - GGG
请参考此帖子以获取答案并解决此问题 https://dev59.com/6LDla4cB1Zd3GeqP3SGQ#53528644 - Ramesh Roddam
嗨,Ramesh,那个链接可能不是你想要粘贴的,它似乎是你对与Spring有关的问题和框架特定的CrossOrigin过滤器的回答。就我所知,如果你看到预检请求但它抱怨没有ok状态,那么从我的经验来看,你要么有另一个错误发生在响应之前,要么OPTIONS不是允许的动词。 - Chris Wood
12个回答

75

我相信这是最简单的示例:

header := w.Header()
header.Add("Access-Control-Allow-Origin", "*")
header.Add("Access-Control-Allow-Methods", "DELETE, POST, GET, OPTIONS")
header.Add("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With")

你还可以为Access-Control-Max-Age添加一个标题,当然你可以允许任何你想要的标头和方法。

最后,你需要响应初始请求:

if r.Method == "OPTIONS" {
    w.WriteHeader(http.StatusOK)
    return
}

编辑(2019年6月):我们现在使用gorilla来完成这个功能。他们的东西得到了更积极的维护,并且他们已经做了很长时间了。保留旧链接,以防万一。

下面是旧的中间件建议:当然,使用中间件可能会更容易些。 我认为我没有使用过它,但这一个似乎受到高度推荐。


你能否澄清一下你所做的与 OP 所做的有何不同?我已经包含了你说的内容,但它对我也不起作用。 - gabopushups
2023年更新:Gorilla项目不再维护。 - jub0bs

48
这篇文章讲解了在任何语言中解决此问题的基本方法及其背后的原理。您正在从一个域(例如 domain-a.com)上运行的 JavaScript 向另一个域(domain-b.com)上运行的 API 请求 URL。当这样做时,浏览器需要询问 domain-b.com 是否允许来自 domain-a.com 的请求。它会发出一个 HTTP OPTIONS 请求以进行确认。然后,在响应中,domain-b.com 上的服务器必须提供(至少)以下 HTTP 标头,以表示“是的,可以允许该请求”。参考:MDN文档相关主题
HTTP/1.1 204 No Content                            // or 200 OK
Access-Control-Allow-Origin: https://domain-a.com  // or * for allowing anybody
Access-Control-Allow-Methods: POST, GET, OPTIONS   // What kind of methods are allowed
...                                                // other headers

如果你在使用谷歌浏览器(Chrome),你可以按F12并进入“网络”标签页,查看服务器domain-b.com所提供的响应内容。
回到 @threeve 原答案中的最基本答案。
header := w.Header()
header.Add("Access-Control-Allow-Origin", "*")

if r.Method == "OPTIONS" {
    w.WriteHeader(http.StatusOK)
    return
}

这将允许来自世界各地的任何人都可以访问这些数据。他包含的其他头文件是出于其他目的而必需的,但这些头文件是最基本的,以满足CORS(跨域资源共享)要求。

实际上,进入网络选项卡并不能告诉你什么。即使控制台选项卡显示跨域头错误,GET请求似乎也是成功的。这在这个答案中有解释。 - clayRay
我认为你正在查看OPTIONS请求,而不是GET请求。在Chrome的网络选项卡中,每个GET请求都应该有2个请求。 - Ryan Shillington
3
这是一个非常详细的答案,成功地解释了通常导致CORS错误的原因。 - mitch

23

后端应该解决CORS问题。 暂时的解决方法 使用此选项。

  1. 打开命令提示符

  2. 导航到chrome安装位置 或者 输入 cd "c:\Program Files (x86)\Google\Chrome\Application" 或者 cd "c:\Program Files\Google\Chrome\Application"

  3. 执行命令 chrome.exe --disable-web-security --user-data-dir="c:/ChromeDevSession"

使用上述选项,您可以打开没有安全性的新chrome。这个chrome不会抛出任何cors问题。

输入图片描述


1
这是唯一对我有效的方法。其他解决方案都没有奏效。 - johnstaveley
1
这也是唯一对我有效的方法!我更喜欢这个解决方案,因为它只建议在我的 DEV 机器上进行更改,我不必担心服务器或其他代码更改。以前我使用 IE 进行开发,在那里我可以禁用 CORS 设置。现在我只剩下 EDGE 和 CHROME 浏览器。我不确定我们是否也可以在 EDGE 浏览器中关闭 CORS 设置。 - Adam
1
谢谢,我也是另一种只有这个解决方案才能工作的情况。 - David Lawson
3
不确定,但在2023年我发现这是唯一适用于我的解决方案。 - fsevenm
1
如果你只是想进行一些本地单元测试,这是一个不错的解决方案。 - Randy Kroeger

16

如果您还没有找到解决方案,并且正在使用以下内容:

  1. AWS HTTP API Gateway;
  2. 您正在使用带有路由和Lambda集成身份验证的任何方法;
  3. 您认为已正确配置了CORS;

错误是因为浏览器在未携带身份验证标头的情况下向您的路由发送预检OPTIONS请求,因此无法获得CORS标头作为响应。

要解决此问题,我添加了另一个OPTIONS方法的路由,不需要进行身份验证,Lambda集成只需返回{ statusCode:200 }即可。


10

在ASP.NET Web API中启用跨域请求 点击了解更多信息

在Web服务应用程序中启用CORS。首先,添加CORS NuGet包。在Visual Studio中,从“工具”菜单中选择NuGet软件包管理器,然后选择包管理器控制台。在包管理器控制台窗口中,键入以下命令:

Install-Package Microsoft.AspNet.WebApi.Cors

此命令将安装最新的包并更新所有依赖项,包括核心Web API库。使用-Version标志来定位特定版本。CORS包需要Web API 2.0或更高版本。

打开文件App_Start/WebApiConfig.cs。将以下代码添加到WebApiConfig.Register方法中:

using System.Web.Http;
namespace WebService
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // New code
            config.EnableCors();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}

接下来,将[EnableCors]属性添加到您的控制器/控制器方法中。

using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Cors;

namespace WebService.Controllers
{
    [EnableCors(origins: "http://mywebclient.azurewebsites.net", headers: "*", methods: "*")]
    public class TestController : ApiController
    {
        // Controller methods not shown...
    }
}

在 ASP.NET Core 中启用跨域请求(CORS)


操作符指定Go语言。 - Luís Soares
Go语言或者axios而不是C#。 - Morlo Mbakop
6
+1 是正确的,原帖指定了 Go 语言,但我来到这里需要一个 aspnet 的解决方案,这篇文章对我很有帮助。 - mamashare

6

Angular 和 Django Rest Framework。

在向我的 DRF API 发送 POST 请求时,我遇到了类似的错误。原来,我只是忘记在端点末尾加上斜杠了。


1
我刚刚花了1个小时来处理这个(Vue.js + Django Rest Framework)的问题。 - Guilherme

3
在我的情况下,这是由于从其他服务复制但放置在错误的位置(顺序很重要!)导致的愚蠢错误。

正确:

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
        {
            app.UseCors(x => x
               .AllowAnyOrigin()
               .AllowAnyMethod()
               .AllowAnyHeader());

            app.UseRouting();
            app.UseStaticFiles();
            app.UseCookiePolicy();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

不正确的:

      public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
      {
        app.UseRouting();
        app.UseStaticFiles();
        app.UseCookiePolicy();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });

        //had no effect
        app.UseCors(x => x
           .AllowAnyOrigin()
           .AllowAnyMethod()
           .AllowAnyHeader());
      }

3

这里提供的解决方案是正确的。但是,同样的错误也可能来自用户错误,即您的端点请求方法与您发送请求时使用的方法不匹配。

例如,服务器端点定义为“RequestMethod.PUT”,而您正在以POST方式请求该方法。


0

对于任何查看此内容并在添加Access-Control-Allow-Origin无结果的人,请尝试添加Access-Control-Allow-Headers。也许可以避免一些头疼。


0
唯一对我有用的是在IIS中创建一个新应用程序,将其映射到完全相同的物理路径,并仅更改身份验证为匿名。

比我还幸运,虽然下面的代码应该可以工作,但是什么都没发生!!!app.UseCors(builder => { builder .AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader(); }); - MC9000

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接