只有在回调/异步函数内部时,Axios 请求才会收到 CORS 错误

Posted

技术标签:

【中文标题】只有在回调/异步函数内部时,Axios 请求才会收到 CORS 错误【英文标题】:Axios request receiving a CORS error only when inside a callback/async function 【发布时间】:2019-08-22 04:10:05 【问题描述】:

我正在将 VueJS 用于我正在构建的应用程序。我拥有的服务器是用 Golang 编写的,并且已设置为接受 CORS。在应用程序中,在我的一个组件searchBar 中,我已将其设置为在创建之前获取一些数据。

var searchBar = 
    prop: [...],
    data: function() 
        return  ... ;
    ,
    beforeCreate: function() 
        var searchBar = this;

        axios.request(
            url: '/graphql',
            method: 'post',
            data: 
                'query': 'coursesid, name'
            
        )
        .then(function(response) 
            searchBar.courses = response.data.data.courses;
        );
    ,
    methods:  ... ,
    template: `...`
;

Axios 在这里完美运行。它得到我需要的数据。 searchBar 有一个按钮,它会导致它发出一个事件,然后由另一个组件searchResults 拾取。收到事件后,searchResults 将获取一些数据。

var searchResults = 
    data: function() 
        return  ... 
    ,
    mounted: function() 
        var sr = this;

        this.$bus.$on('poll-server', function(payload) 
            var requestData = 
                url: '/graphql',
                method: 'post',
                data:  ... ,
                ...
            ;
            ...

            axios.request(requestData)
                 .then(function(response) 
                     console.log(response);
                 
            );
        );
    ,
    template: `...`
;

请注意,我的 Axios 请求调用现在位于回调函数中。执行此调用时,我收到一个 CORS 错误:

从源“http://127.0.0.1:8080”访问“http://127.0.0.1:9000/graphql”处的 XMLHttpRequest 已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:没有“Access-Control-Allow-Origin”标头出现在请求的资源上。

我的服务器位于http://127.0.0.1:9000,客户端位于http://127.0.0.1:8080。这是第二次请求调用的OPTIONS请求的内容。

为了比较,这里是第一个请求调用的请求标头(有效!)。

我已经将我的 Golang 服务器设置为通过 go-chi/cors 支持 CORS。就是这样设置的。

router := chi.NewRouter()
...    
// Enable CORS.
cors := cors.New(cors.Options
    AllowedOrigins:   []string"*",
    AllowedMethods:   []string"POST", "OPTIONS",
    AllowedHeaders:   []string"Accept", "Authorization", "Content-Type", "X-CSRF-Token",
    ExposedHeaders:   []string"Link",
    AllowCredentials: true,
    MaxAge:           300,
)

router.Use(
    render.SetContentType(render.ContentTypeJSON),
    middleware.Logger,
    middleware.DefaultCompress,
    middleware.StripSlashes,
    middleware.Recoverer,
    cors.Handler,
)

router.Post("/graphql", gqlServer.GraphQL())

return router, db

是什么导致了我遇到的错误以及如何解决?

【问题讨论】:

不熟悉 go-chi/cors,但您确定 CORS 设置正确吗?您的第一个 POST 请求很可能是正确的,但对于第二个 GET 请求却不是。该错误清楚地显示第二个 API 上没有 Allowed Origin 标头。 @colminator 我不小心留下了第二个请求的详细信息。第二个请求也是POST 请求。 请检查发送到服务器的OPTIONS 请求和响应,如果可以,请在此处发布 @BenYaakobi,我已将OPTIONS 请求添加到问题中。 @RejoanulAlam,是的,对于本地测试,不需要安全性。但是,最好将 dev/local 与生产中的内容相匹配。 【参考方案1】:

预计会出现此 CORS 错误。您使用的 CORS 插件会为您请求过滤。如果您查看允许的标头列表,您会发现它缺少您尝试在 axios 调用中发送的名为 snb-user-gps-location 的标头。

要么将该标头添加到允许列表中,要么不从前端发送。

【讨论】:

哇!我不认为我的自定义标题丢失导致了我的问题。我已经确认这确实是解决方法。非常感谢! 它还显示了发布与您的问题相关的所有代码的重要性,如果我没有查看您的请求的第一个屏幕截图,我永远不会发现这是您的错误,因为该屏幕截图是唯一提到此标题的地方【参考方案2】:

我仍然怀疑 go-chi CORS 设置。我建议您手动设置 CORS。这并不难。此页面将获得基本设置:https://flaviocopes.com/golang-enable-cors/

如果这适用于您的嵌套 API 设置,那么我们可以向后确定 go-chi 配置问题。


更新:

我还将调查其他中间件步骤 - 注释掉所有非必要的步骤。

中间件处理程序通常检查r *http.Request 或将标头写入w http.ResponseWriter,然后最终处理程序将写入响应正文。但是在整个中间件链中,以下标头/正文写入流程应该看起来像这两个流程之一:

成功:

w.Header().Set(...) // headers
w.Write(...) // body

请注意,上述流程将发出隐式的 http 状态代码写入,以保持标题出现 first 和正文 second

w.Header().Set(...) // headers
w.WriteHeader(http.StatusOK) // implicit success http status code
w.Write(...) // body

失败:

如果报告运行时错误,流程应该是:

w.Header().Set(...) // headers
w.WriteHeader(http.StatusInternalServerError) // some unrecoverable error 
w.Write(...) // optional body

之所以提出这个问题,是因为我看到了 3 种类型的错误,这些错误会扰乱这个流程:

错误的中间件处理程序在正文之后写入标头导致客户端混淆 调用 http.Error 认为会停止 API 死机 - 而不是在 http.Error 之后立即返回并且确保不会调用后续中间件处理程序 两次写入相同的标头。在后续处理程序中重写标头将导致客户端看到最后一个版本(从而破坏任何以前的版本)

因此,为了全面追踪事情,我会 log.Println 为您的 API 写入所有标头/正文,以确保上述流程正确且没有预期值被覆盖。

【讨论】:

双 API?我一定把你弄糊涂了。我道歉。这些请求正在调用同一个 API。 我理解你的代码。在你调用它两次的意义上加倍。 哦。我知道了。我认为双重 API 设置具有误导性。无论如何,也许手动设置它是可行的。 最后一个想法:在(2nd)API调用的处理程序中是否有任何可能的http错误报告?如果是这样,从 header-writes 乱写错误代码可能会导致 headers(在这种情况下为 Origin)永远不会被发送。 显然,我的问题是由于我的自定义标头未包含在允许的标头中。 Ferrybig here 指出并解决了这个问题。不过,感谢您的努力。

以上是关于只有在回调/异步函数内部时,Axios 请求才会收到 CORS 错误的主要内容,如果未能解决你的问题,请参考以下文章

在异步函数内部,从回调函数返回值返回 Promise(undefined) [重复]

在异步函数内部,从回调函数返回值返回 Promise(undefined) [重复]

JavaScript的异步编程

如何使用 sinon 使用 axios.post 模拟异步方法?

如何在收到异步函数的回调之前使线程休眠?

同步异步 + 回调函数