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請求都和簡單請求同樣。

相關文章
相關標籤/搜索