php 跨域问题

/**
 * 跨域请求设置
 */
function checkAllowOrigin()
{
    //从配置文件获取允许源域名
    $allowOrigin = explode(',', env('app.allow_origin'));
    if (in_array('*', $allowOrigin)) {
        $origin = '*';
        $allow = true;
    } else {
        $origin = request()->header('Origin') ?? request()->domain();
        $allow = in_array($origin, $allowOrigin);
    }

    if (!$allow) {
        exit('403');
    }

    //允许跨域的来源域名
    header('Access-Control-Allow-Origin:'.$origin); 
    header('Access-Control-Allow-Methods: GET, POST, OPTIONS');//允许跨域的请求方法
    // 带 cookie 的跨域访问
    header('Access-Control-Allow-Credentials: true');
    // 响应头设置(允许跨域的头部)
    header('Access-Control-Allow-Headers:x-requested-with,Content-Type,X-CSRF-Token,Access-Token');
}

四点:

 1.允许跨域的来源域名

 2.允许跨域的请求方法

 3.允许带 cookie 的跨域访问(不允许改为false)

4.允许跨域的头部(记得把自定义的header头也写进去,不然跨域会不成功)

特别要注意的是3和4点。比如第4点的Access-Token,我们项目自定义的,忘了加。在有用户登陆的时候,就一直无法跨域。

踩坑记

前端(A域名)vue,axios访问本地(C域名)接口,没问题;访问线上接口(B域名),总报一下错误:

Access to XMLHttpRequest at 'http:/B.cn/teacher/auth/nearTeacher' from origin 'http://A.coom' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

而访问 http:/B.cn/api/XXX 接口,这么都没有问题。

自己写个简单vue请求线上接口,没问题

<script>
new Vue({
  el: '#app',
  data () {
    return {
      info: null
    }
  },
  mounted () {
    axios.defaults.withCredentials = true;
    axios
      .post('http://B.cn/teacher/auth/nearTeacher')
      .then(response => (this.info = response))

   axios({

  method: 'post',

  url: 'http://alone.seeonce.me/teacher/auth/nearTeacher',

  withCredentials: true

 })

  }
})
</script>

反复确认线上跨域有设置 header('Access-Control-Allow-Credentials: true');

反复确认线上代码配置和本地一样,线上缓存清除,问题都还是如此。

点开谷歌浏览器查看NetWork-》other,可以看到OPTIONS请求204,但肯定有问题

在代码里把跨域的代码都搬到index.php里面了,结果发现还是问题如此

此刻我觉得应该是nginx配置问题:

结果发现:本地nginx配置没有配置跨域,而线上有,但是线上漏了个add_header 'Access-Control-Allow-Credentials' 'true';

  location / {

  if ($request_method = 'OPTIONS') {
    add_header 'Access-Control-Allow-Origin' "$http_origin";
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Access-Token,Content-Range,Range';
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Max-Age' 7200;
    add_header 'Content-Type' 'text/json; charset=utf-8';
    add_header 'Content-Length' 0;
    return 204;
  }

 }

所以OPTION的时候才会一直返回204,拦截住了

结论:

1.访问thinkphp的api模块不走OPTION或者前端vue没有设置 withCredentials = true

2.自己写的vue,具备withCredentials = true(测试过,php代码关掉就会出错),但是nignx配置控制不到。可能没走OPTIONS。

3.nignx配置没配置到这的问题,加上问题就都解决了。nignx只控OPTIONS这关,真实请求POST还需要php代码在控制一次。