php跨域问题记录

记录跨域问题

1、问题

在控制层加了以下代码:php

header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN'] );
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Headers: X-Requested-With,Content-Type,Accept');

打开chrome的network里的response,没有这几个值~html

可是一样的代码我在本地另外一个项目里是OK的,项目环境是Nginx作了层代理,实际用的是PHP当Apache模块的方式,就开始怀疑:前端

  • 输出时框架限制了
  • Nginx/Apache限制了header(ps:咱们项目是用Nginx当了反向代理,PHP当Apache模块)
  • 灵魂拷问:PHP输出时这些header是怎么返回的?

2、解决

1.框架

用xdebug跟了下,没看到框架里有任何限制不能更改headerweb

2.web服务器

看到response每次返回的都同样,觉得是运维控制了返回的选项,不能随意添加,和运维同事沟通了下,发现确实是不能随意添加header头,窃喜觉得找到了缘由。然而另外一个同事说加的跨域容许是OK的;Nginx的conf里加的proxy 也是把Apache返回的header都返回了,排除ajax

3.文件问题

从新思考,跨域问题是浏览器控制的,只要HTTP协议里返回的access容许就能够了。chrome

使用header_list()方法打印了下发送的header列表,发现本身写的那几个没返回。数据库

换种思路,把这几行加到其余文件,发现能够,而后对比俩文件有啥区别,最后最后的缘由是<?php这个标识是从第2行开始写的,即在header方法以前有了输出。json

3、补充

1.同源策略

参考:跨域

浏览器同源政策及其规避方法浏览器

跨域资源共享CORS详解

浏览器安全的基石是"同源政策",若是非同源,共有3种行为受到限制

  • cookie、LocalStorage和IndexDB(浏览器提供的本地数据库)没法读取
  • dom没法得到(如iframe和window.open若是不一样源,就没法通讯)
  • ajax请求不能发送

这里主要讨论下ajax的跨域解决方法,

2.跨域解决方式:

  • jsonp
  • cors
  • 反向代理

2.1 jsonp

全称:json for padding 本质是用<script>标签能够跨域访问的性质,动态建立一个script,而后回调js数据脚本,请求类型是js而非xhr.普通接口返回的是数据对象,而jsonp是js数据脚本

2.2 CORS

CORS是一个W3c标准,全称是“跨域资源共享”(cross-origin resource sharing),容许浏览器向跨源服务器,发出XMLHttpRequest请求。

须要浏览器和服务器同时支持。目前全部浏览器都支持该功能,整个cors通讯过程不须要用户参与。

浏览器将cors请求分为两种:简单请求和非简单请求

只要同时知足如下两个条件,就属于简单请求:

(1) 请求方法是如下三种方法之一:

HEAD
    GET
    POST

(2)HTTP的头信息不超出如下几种字段:

Accept
    Accept-Language
    Content-Language
    Last-Event-ID
    Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

不然属于非简单请求。

2.2.1 简单请求

浏览器在头信息中增长一个origin字段,用来讲明本次请求来自哪一个源(协议+域名+端口)。服务器根据这个值决定是否赞成此次请求。

若是服务器没有返回access这样的头部信息,即服务器没支持的话,前端的console里会显示access to xmlHttpRequest ...has been blocked by CORS policy...

若是origin指定的域名在许可范围内,服务器返回的响应会多出几个头信息字段:

Access-Control-Allow-Origin: xxxx
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: xxx

Access-Control-Allow-Origin:

是必须的,值要么是请求时origin字段的值,要么是*表示接受任意域名的请求。

Access-Control-Allow-Credentials

可选,布尔值,表示是否容许发送cookie,不一样源时请求中不会带cookie,设为true表示服务器许可cookie能够包含在请求中,
XMLHttpRequest.withCredentials属性是一个boolean类型,表示是否该使用cookie,authorization header(头部受权)或者TLS客户端证书这一类资格证书来建立一个跨站点访问控制请求。

参考:
xmlHttpRequest.withCredentials

Access-Control-Expose-Headers

可选,cors请求时,xmlHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。若是想拿到其余字段,就必须在Access-Control-Expose-Headers里面指定。

若是要带上cookie,后台的origin就不能设为*,且须要前端设置以下:

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
2.2.2 非简单请求

是对服务器有特殊请求的:如请求方法是put或delete,或者content-type字段的类型是application/json.

非简单请求会在正式通讯以前,增长HTTP查询请求,称为预检请求。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单中,以及可使用那些HTTP动词和头信息字段。只有获得确定答复,浏览器才会发出正式的XMLHttpRequest请求,不然就报错。

预检请求

1)请求:

预检请求用的方法是option,表示这个请求时用来询问的。头信息里关键字段是origin表示请求来自哪一个源。

2)回应:

服务器收到预检请求后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段之后,确认容许跨源请求,就能够作出回应。

服务器返回的Access-Control-Max-Age
该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即容许缓存该条回应1728000秒(即20天),在此期间,不用发出另外一条预检请求

一旦服务器经过了预检请求,之后每次浏览器正常的cors请求都和简单请求同样。

相关文章
相关标签/搜索