axios跨域请求

工作中遇到的一个axios跨域请求问题,记录下最终的解决方法。

问题描述

前端用Vue,引入了axios,调用的是rails项目中的接口。vue 2.5.17 , rails 5.2.1

Vue项目中,配置文件含如下内容:

  axios: {
    // See https://github.com/nuxt-community/axios-module#options
    baseURL:
      process.env.NODE_ENV === 'production'
        ? 'https://xxxxxx/v2'
        : 'http://api.xxxxx:3000/v2',
    credentials: true
  },

设置credentials为true,axios请求时,会自动携带cookie。本地运行 yarn run dev,设置端口为4000.

浏览器打开localhost:4000, 没有任何反应,查看chrome 开发者模式下的console,出现如下报错:

Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

解决方法

需要在rails项目中,安装gem rack-cors

gem 'rack-cors', :require => 'rack/cors'

bundle后,在config/application.rb文件中,添加如下语句:

    config.middleware.insert_before 0, Rack::Cors do
      allow do
        origins '*'
        resource '*', headers: :any, methods: [:get, :post, :options]
      end
    end

重启rails项目。

这时,本地再次访问locahost:4000,如果console依然报错:

Access to XMLHttpRequest at 'http://api.xxxxx:3000/v2' from origin 'http://localhost:4000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

请修改rails项目的config/application.rb文件,在resource中添加credentials: true,同时设置origins,添加正则来限定请求访问的来源地址,如果只是单单添加credentials: true,重启rails时,Rack::Cors会弹出报错:

Allowing credentials for wildcard origins is insecure. Please specify more restrictive origins or set 'credentials' to false in your CORS configuration. (Rack::Cors::Resource::CorsMisconfigurationError)

最终添加到config/application.rb文件的配置内容如下:

    config.middleware.insert_before 0, Rack::Cors do
      allow do
        origins %r{/A***your-regex***\z/}x
        resource '*', headers: :any, methods: [:get, :post, :options], credentials: true
      end
    end

重启rails项目。

再次访问,OK。

参考

如何使用 Rails 建立可跨域访问的 API?