重學前端(8)封裝ajax,http,跨域問題

前端_小牛_到犀牛發表於2019-06-04

前言

  • 當我們熟練的使用axios,fetch,promise的時候是否還會想起,當年的ajax,讓我們來重溫ajax原理,感受一下經典

http 協議

HTTP協議,即超文字傳輸協議(Hypertext transfer protocol)。是一種詳細規定了瀏覽器和伺服器之間互相通訊的規則

HTTP協議規定了請求響應 的標準

請求與請求報文

get請求的請求報文詳解

//--------------------------請求行--------------------------------
// GET  請求方式
// 01.php?username=pp&password=123456    請求路徑+引數(注意點)
// HTTP/1.1 HTTP的版本號
GET /day02/01.php?username=pp&password=123456 HTTP/1.1

//--------------------------請求頭--------------------------------
Host: www.study.com
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,`*/*`;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6

//----------------------------請求體-------------------------------------
//get請求沒有請求體,但是引數會拼接到請求行中
複製程式碼

POST請求的請求報文

//-----------------------請求行---------------------------------------------
POST /01.php HTTP/1.1

//-----------------------請求頭--------------------------------------------
Host: www.study.com
Connection: keep-alive
//傳遞的引數的長度。
Content-Length: 29
Cache-Control: max-age=0
Origin: http://www.study.com
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36
//內容型別:表單資料,如果是post請求,必須指定這個屬性。
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,`*/*`;q=0.8
Referer: http://www.study.com/01-login.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6

//------------------------請求體------------------------------------------
username=why&password=123456
複製程式碼

GET請求與POST請求的對比

  • GET請求沒有請求體,因為GET請求的引數拼接到位址列中了
  • POST請求有請求體,就是傳遞的引數
  • POST請求需要指定content-type屬性。

響應與響應報文

//---------------------狀態行(響應行)-------------------------------
//HTTP/1.1  HTTP版本
//200 響應的狀態
	//200表示成功
	//304表示讀快取
	//404表示找不到資源
	//500表示服務端錯誤
HTTP/1.1 200 OK

//----------------------響應頭-----------------------------------------------
Date: Thu, 22 May 2019 16:51:22 GMT
Server: Apache/2.4.23 (Win32) OpenSSL/1.0.2j PHP/5.4.45
X-Powered-By: PHP/5.4.45
Content-Length: 18
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
//內容型別,告訴瀏覽器該如何解析響應結果
Content-Type: text/html;charset=utf-8
//-----------------------響應體------------------------------------------------
hello world
複製程式碼

AJAX

即 Asynchronous [e'sɪŋkrənəs] Javascript And XML, AJAX 不是一門的新的語言,而是對現有技術的綜合利用。 本質是在HTTP協議的基礎上以非同步的方式與伺服器進行通訊。

同步與非同步

同步和非同步概念:

同步: 指的就是事情要一件一件做。等做完前一件才能做後一件任務

非同步: 不受當前任務的影響,兩件事情同時進行,做一件事情時,不影響另一件事情的進行。

程式設計中:非同步程式程式碼執行時不會阻塞其它程式程式碼執行,從而提升整體執行效率。

網頁非同步應用:

  1. 驗證你的使用者名稱是否已經存在(一邊輸入,一邊獲取你的資訊,和後臺比對)。
  2. 百度搜尋提示,及相關內容展示(一邊輸入,一邊找出了你可能要的內容)。
  3. 新浪微博評論(非同步載入)。

XMLHttpRequest可以以非同步方式的請求資料處理程式, 可實現對網頁的部分更新, 而不是重新整理整個頁面

XMLHttpRequest物件

瀏覽器內建物件,用於與伺服器通訊(交換資料) , 由此我們便可實現對網頁的部分更新,而不是重新整理整個頁面。這個請求是非同步的,即在往伺服器傳送請求時,並不會阻礙程式的執行,瀏覽器會繼續渲染後續的結構。

請求由客戶端發起,其規範格式為:請求行、請求頭、請求主體。
複製程式碼

傳送get請求

XMLHttpRequest以非同步的方式傳送HTTP請求,因此在傳送請求時,一樣需要遵循HTTP協議。

使用XMLHttpRequest傳送get請求的步驟

//1. 建立一個XMLHttpRequest物件
var xhr = new XMLHttpRequest();

//2. 設定請求行
// 第一個引數:請求方式  get/post
// 第二個引數:請求的地址 需要在url後面拼上引數列表
xhr.open("get", "01.php?name=why");

//3. 設定請求頭
//請求頭中可以設定Content-Type,用以說明請求主體的內容是如何編碼,get請求時沒有請求體,無需設定

//4. 設定請求體
//get請求的請求體為空,因為引數列表拼接到url後面了
xhr.send(null);
複製程式碼

注意點 :

  • get請求,設定請求行時,需要把引數列表拼接到url後面
  • get請求不用設定請求頭, 不用說明請求主體的編碼方式
  • get請求的請求體為null

傳送post請求

var xhr = new XMLHttpRequest();

// 1. 設定請求行 post請求的引數列表在請求體
xhr.open("post", "02.php");

// 2. 設定請求頭, post 請求必須要設定 content-type, 標記請求體內容的解析方式, 不然後端無法解析獲取資料
xhr.setRequestHeader( "content-type", "application/x-www-form-urlencoded" );

// 3. 設定請求體
xhr.send( "name=Jepson&age=18" );
複製程式碼

注意點 :

  • post請求, 設定請求行時, 不拼接引數列表
  • post必須設定請求頭中的content-type為application/x-www-form-urlencoded, 標記請求體解析方式
  • post 請求需要將引數列表設定到請求體中

獲取響應 readyState

readyState:記錄了XMLHttpRequest物件的當前狀態

readyState有五種可能的值:
xhr.readyState = 0時,UNSENT open尚未呼叫
xhr.readyState = 1時,OPENED open已呼叫
xhr.readyState = 2時,HEADERS_RECEIVED 接收到頭資訊
xhr.readyState = 3時,LOADING 接收到響應主體
xhr.readyState = 4時,DONE 響應完成

不用記憶狀態,只需要瞭解有狀態變化這個概念
複製程式碼

HTTP響應分為3個部分,狀態行、響應頭、響應體。

//給xhr註冊一個onreadystatechange事件,當xhr的狀態發生狀態發生改變時,會觸發這個事件。
xhr.onreadystatechange = function () {
  
  if(xhr.readyState == 4){
    
    //1. 獲取狀態行
    console.log("狀態行:"+xhr.status);
    
    //2. 獲取響應頭
    console.log("所有的響應頭:"+xhr.getAllResponseHeaders());
    console.log("指定響應頭:"+xhr.getResponseHeader("content-type"));
    
    //3. 獲取響應體
    console.log(xhr.responseText);
    
  }
  
}
複製程式碼

資料互動

瀏覽器端只是負責使用者的互動和資料的收集以及展示,真正的資料都是儲存在伺服器端的。

我們現在通過ajax的確可以返回一些簡單的資料(一個字串), 
但是在實際開發過程中,肯定會會設計到大量的複雜型別的資料傳輸,
比如陣列、物件等,但是每個程式語言的語法都不一樣。

因此我們會採用通過的資料交換格式(XML、JSON)來進行資料的互動。
複製程式碼

XML(瞭解即可,現在很少見)

什麼是XML

  • XML 指可擴充套件標記語言(EXtensible Markup Language)
  • XML 是一種標記語言,很類似 HTML
  • XML 的設計宗旨是傳輸資料,而非顯示資料
  • XML 標籤沒有被預定義。您需要自行定義標籤。

語法規範

  • 第一行必須是版本資訊
  • 必須有一個根元素(有且僅有一個)
  • 標籤不可有空格、不可以數字或.開頭、大小寫敏感
  • 不可交叉巢狀,都是雙標籤,如果是單標籤,必須閉合
  • 屬性雙引號(瀏覽器自動修正成雙引號了)
  • 特殊符號要使用實體
  • 註釋和HTML一樣
<?xml version="1.0" encoding="utf-8" ?>
<students>
    <student>
        <name>張三</name>
        <age>18</age>
        <gender></gender>
        <desc>路人甲</desc>
    </student>
    <student>
        <name>李四</name>
        <age>20</age>
        <gender></gender>
        <desc>路人乙</desc>
    </student>
</students>
複製程式碼

php獲取xml檔案的內容

// 注意: 如果需要返回 xml 資料, 需要將 content-type 改成 text/xml, 不然瀏覽器以 text/html 解析
header( 'content-type:text/xml;charset=utf-8' );
// file_get_content 用於獲取檔案的內容
// 引數: 檔案的路徑
$result = file_get_content( "data.xml" );
echo $result;
複製程式碼

js解析xml

//獲取服務端返回的xml資料,需要使用xhr.responseXML,這是一個document物件,可以使用DOM中的方法查詢元素。
var data = xhr.responseXML;
//獲取所有的學生
var students = data.querySelectorAll("student");
複製程式碼

缺點:雖然可以描述和傳輸複雜資料,但是其解析過於複雜, 並且體積較大,所以實現開發已經很少使用了。

JSON資料

JSON(JavaScript Object Notation, JS 物件標記) 是一種輕量級的資料交換格式。它基於 ECMAScript 規範,採用獨立於程式語言的文字格式來儲存和表示資料。

  • 資料在 鍵值對 中
  • 資料由逗號分隔(最後一個 鍵值對 不能帶逗號)
  • 花括號儲存物件,方括號儲存陣列
  • 鍵使用雙引號
var obj = {a: 'Hello', b: 'World'}; //這是一個物件

// 這是一個 JSON 字串,本質是一個字串
var json = '{"a": "Hello", "b": "World"}';
複製程式碼

JSON資料在不同語言進行傳輸時,型別為字串,不同的語言各自也都對應有解析方法,解析完成後就能很方便的使用了

php處理json

  • php關聯陣列 ==> json ( json_encode )
// php的關聯陣列
$obj = array(
  "a" => "hello",
  "b" => "world",
  "name" => "why"
);
//json字串
$json = json_encode( $obj );
echo $json;
複製程式碼
  • json ==> php物件/關聯陣列 ( json_decode )
$json = '{"a": "Hello", "b": "World"}';//json字串
//第一個引數:json字串
//第二個引數:
//false,將json轉換成物件(預設)
//true:將json轉換成陣列(推薦)
$obj = json_decode($json,true);
echo $obj['a'];

//通過json檔案獲取到的內容就是一個json字串。
$data = file_get_contents("data.json");

//將json轉換成陣列
$result = json_decode($data, true);
print_r($result);
複製程式碼

JS處理json

  • JS物件 ==> JSON字串 JSON.stringify(obj)
    //obj是一個js物件
    var obj = {a: 'Hello', b: 'World'}
    //result就變成了一個json字串了
    var result = JSON.stringify(obj);// '{"a": "Hello", "b": "World"}'
複製程式碼
  • JSON字串 ==> JS物件 JSON.parse(obj)
    //json是一個json字串
    var json = '{"a": "Hello", "b": "World"}';
    //obj就變成了一個js物件
    var obj = JSON.parse(json);// {a: 'Hello', b: 'World'}
複製程式碼

相容性處理

現在一般最多相容到 IE8, 這裡以後見到了知道是在處理相容性就行了

var xhr = null;
if(XMLHttpRequest){
  //現代瀏覽器 IE7+
  xhr = new  XMLHttpRequest();
}else{
  //老版本的 Internet Explorer (IE5 和 IE6)使用 ActiveX 物件:
  xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
複製程式碼

封裝ajax工具函式

每次傳送ajax請求,其實步驟都是一樣的,重複了大量程式碼,我們完全可以封裝成一個工具函式。

//1. 建立xhr物件
//2. 設定請求行
//3. 設定請求頭
//3. 設定請求體
//4. 監聽響應狀態
//5. 獲取響應內容
複製程式碼

引數提取

引數名 引數型別 描述 傳值 預設值
type string 請求方式 get/post 只要不傳post,就是get
url string 請求地址 介面地址 如果不傳地址,不傳送請求
async boolean 是否非同步 true/fase 只要不傳false,那就是true,非同步請求
data object 請求資料 {key:value,key1:value2} 需要把這個物件拼接成引數的格式 uname=hucc&upass=12345
dataType string 返回的資料型別 xml/json/text text
success function 響應成功時呼叫 - -
error function 響應失敗時呼叫 - -

引數檢測

// 要求引數obj必須傳遞,否則直接不傳送請求
if(!obj || typeof obj !== "object"){
  return;
}
// 如果type傳遞的是post,那就傳送post請求,否則傳送get請求
var type = obj.type == "post"?"post":'get';
var url = obj.url;
if(!url){
  return;
}
// 只有當async傳遞了false,才會傳送同步請求,不然只傳送非同步請求
var async = obj.async == false? false:true;
複製程式碼

完整版本

var $ = {
  ajax: function (options) {
    //如果options引數沒有傳遞,直接返回。
    if (!options || typeof options !== "object") {
      return;
    }
    
    //處理預設引數
    //如果引數不是post,那就預設為get
    var type = options.type == "post" ? "post" : "get";
    //如果沒有傳url,那就傳當前地址
    var url = options.url || location.pathname;
    //如果引數不是false,那就預設是true,發非同步請求
    var async = options.async == false ? false : true;
    
    var params = this.getParams(options.data);
    
    var xhr = new XMLHttpRequest();
    
    //設定請求行
    if (type == "get") {
      url = url + "?" + params;
    }
    xhr.open(type, url, async);
    
    //設定請求頭
    if (type == "post") {
      xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
    }
    //設定請求引數
    xhr.send(params);
    
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4) {
        if (xhr.status == 200) {
          /*根據響應頭的content-type屬性指定方法接收到的內容*/
          var contentType = xhr.getResponseHeader('content-type');
          var data = null;
          if (contentType.indexOf('json') > -1) {
            data = JSON.parse(xhr.responseText);
          } else if (contentType.indexOf('xml') > -1) {
            data = xhr.responseXML;
          } else {
            data = xhr.responseText;
          }
          /*執行成功函式*/
          options.success && options.success(data);
        } else {
          options.error && options.error(xhr.responseText);
        }
        
      }
    }
  },
  getParams: function (obj) {
    //將obj物件轉換成引數
    //將物件轉換成引數列表
    if (!obj) {
      return null;
    }
    var arr = [];
    for (var k in obj) {
      arr.push(k + "=" + obj[k]);
    }
    return arr.join("&");
  }
  
}
複製程式碼

jQuery中的ajax方法

jQuery為我們提供了更強大的Ajax封裝

$.ajax

引數列表

引數名稱 描述 取值 示例
url 介面地址 url:"02.php"
type 請求方式 get/post type:"get"
timeout 超時時間 單位毫秒 timeout:5000
dataType 伺服器返回的格式 json/xml/text(預設) dataType:"json"
data 傳送的請求資料 物件 data:{name:"zs", age:18}
beforeSend 呼叫前的回撥函式 function(){} beforeSend:function(){ alert(1) }
success 成功的回撥函式 function (data) {} success:function (data) {}
error 失敗的回撥函式 function (error) {} error:function(data) {}
complete 完成後的回撥函式 function () {} complete:function () {}

使用示例:

$.ajax({
  type:"get",//請求型別
  url:"02.php",//請求地址
  data:{name:"zs", age:18},//請求資料
  dataType:"json",//希望接受的資料型別
  timeout:5000,//設定超時時間
  beforeSend:function () {
    //alert("傳送前呼叫");
  },
  success:function (data) {
    //alert("成功時呼叫");
    console.log(data);
  },
  error:function (error) {
    //alert("失敗時呼叫");
    console.log(error);
  },
  complete:function () {
    //alert("請求完成時呼叫");
  }
});
複製程式碼

其他api

//$.post(url, callback, [dataType]);只傳送post請求
//$.get(url, callback, [dataType]);
//$.getJSON(url, callback);
//$.getScript(url,callback);//載入伺服器端的js檔案
//$("div").load(url);//載入一個伺服器端的html頁面。
複製程式碼

同源與跨域

同源

同源策略的基本概念

1995年,同源政策由 Netscape 公司引入瀏覽器。目前,所有瀏覽器都實行這個政策。 同源策略:最初,它的含義是指,A網頁設定的 Cookie,B網頁不能開啟,除非這兩個網頁"同源"。所謂"同源"指的是"三個相同"。

協議相同
域名相同
埠相同
複製程式碼

舉例來說,這個網址http://www.example.com/dir/page.html協議是http://

域名是www.example.com,埠是80(預設埠可以省略)。它的同源情況如下。

http://www.example.com/dir2/other.html:同源

file:///F:/phpStudy/WWW//04.html 不同源(協議不同)
http://v2.www.example.com/dir/other.html:不同源(域名不同)
http://www.example.com:81/dir/other.html:不同源(埠不同)
複製程式碼

同源策略的目的

同源政策的目的,是為了保證使用者資訊的安全,防止惡意的網站竊取資料。

同源策略的限制範圍

隨著網際網路的發展,“同源策略”越來越嚴格,目前,如果非同源,以下三種行為都將收到限制。

1. Cookie、LocalStorage 和 IndexDB 無法讀取。
2. DOM 無法獲得。
3. AJAX 請求不能傳送。
複製程式碼

雖然這些限制是很有必要的,但是也給我們日常開發帶來不好的影響。比如實際開發過程中,往往都會把伺服器端架設到一臺甚至是一個叢集的伺服器中,把客戶端頁面放到另外一個單獨的伺服器。那麼這時候就會出現不同源的情況,如果我們知道兩個網站都是安全的話,我們是希望兩個不同源的網站之間可以相互請求資料的。這就需要使用到跨域

跨域

jsonp( 無相容性問題 )

JSONP(JSON with Padding)、可用於解決主流瀏覽器的跨域資料訪問的問題。

原理:服務端返回一個定義好的js函式的呼叫,並且將伺服器的資料以該函式引數的形式傳遞過來,這個方法需要前後端配合

script 標籤是不受同源策略的限制的,它可以載入任意地方的 JavaScript 檔案。類似的還有imglink標籤

<!--不受同源策略限制的標籤-->
<img src="http://www.api.com/1.jpg" alt="">
<link rel="stylesheet" href="http://www.api.com/1.css">
<script src="http://www.api.com/1.js"></script>
複製程式碼

jsonp演化過程1

php檔案

header("content-type:text/html;charset=utf-8");
echo "alert(1111)";
複製程式碼

html檔案

<script src="http://www.api.com/testjs.php"></script>
複製程式碼

原理:其實src的路徑是什麼檔案不重要,無論引入js檔案還是php檔案,最後返回給瀏覽器的都是字串,因此我們script標籤是可以引入一個php檔案的。

jsonp演化過程2

php檔案

header("content-type:text/html;charset=utf-8");
echo "var a = 118;";
複製程式碼

html檔案

<script src="http://www.api.com/testjs.php"></script>
<script>
  //a列印出來了118
  console.log(a);
</script>
複製程式碼

我們現在做到了一件事情,從不同源的php檔案中獲取到了資料

缺點:獲取資料的script標籤必須寫在使用的script標籤的前面,必須保證先有資料才能對資料進行渲染。

jsonp演化過程3

php程式碼

header("content-type:text/html;charset=utf-8");
$arr = array(
    "name"=>"zs",
    "age"=>18
);
$result = json_encode($arr);
//這是一段js函式的呼叫的程式碼,$result就是我們想要的資料
echo "func($result)";
複製程式碼

js程式碼

<script>
  function func(data) {
    console.log(data);
  }
</script>
<script src="http://www.api.com/testjs.php"></script>
複製程式碼

缺點:後端必須知道前端宣告的方法的名字,後端才能呼叫。

jsonp演化過程4

php程式碼

header("content-type:text/html;charset=utf-8");
$arr = array(
    "name"=>"zs",
    "age"=>18
);
$result = json_encode($arr);
//這是一段js函式的呼叫的程式碼,$result就是我們想要的資料
echo $_GET['callback']."($result)";
複製程式碼

javascript程式碼

function fun(data) {
  console.log(data);
}
var button = document.querySelector("button");
button.onclick = function () {
  var script = document.createElement("script");
  script.src = "http://www.api.com/testjs.php?callback=fun";
  document.body.appendChild(script);
}
複製程式碼
  1. 說白了,jsonp的原理就是 藉助了script標籤 src 請求資源時, 不受同源策略的限制.
  2. 在服務端返回一個函式的呼叫,將資料當前呼叫函式的實參。
  3. 在瀏覽器端,需要程式要宣告一個全域性函式,通過形參就可以獲取到服務端返回的對應的值

jsonp原理大家需要知道,但不用太過於去糾結這個原理,因為jquery已經幫我們封裝好了,我們使用起來非常的方便。

jquery對於jsonp的封裝

//使用起來相當的簡單,跟普通的get請求沒有任何的區別,只需要把dataType固定成jsonp即可。
$.ajax({
  type:"get",
  url:"http://www.why.com/testjs.php",
  dataType:"jsonp",
  data:{
    uname:"why",
    upass:"123456"
  },
  success:function (info) {
    console.log(info);
  }
});
複製程式碼

XMLHttpRequest2.0

XMLHttpRequest是一個javascript內建物件,使得Javascript可以進行非同步的HTTP通訊。2008年2月,就提出了XMLHttpRequest Level 2 草案。

老版本的XMLHttpRequest的缺點:

1. 僅支援傳輸文字資料,無法傳說二進位制檔案,比如圖片視訊等。
2. 傳輸資料時,沒有進度資訊,只能提示完成與否。
3. 受到了"同源策略"的限制
複製程式碼

新版本的功能:

1. 可以設定timeout超時時間
2. 可以使用formData物件管理表單資料
3. 允許請求不同域名下的資料(跨域)
4. 支援上傳二進位制檔案
5. 可以獲取資料傳輸的進度資訊
複製程式碼

注意:我們現在使用new XMLHttpRequest建立的物件就是2.0物件了,我們之前學的是1.0的語法,現在學習一些2.0的新特性即可。

timeout設定超時

xhr.timeout = 3000;//設定超時時間
xhr.ontimeout = function(){
  alert("請求超時");
}
複製程式碼

formData管理表單資料

formData物件類似於jquery的serialize方法,用於管理表單資料

使用特點: 
1. 例項化一個formData物件, new formData(form); form就是表單元素
2. formData物件可以直接作為 xhr.send(formData)的引數。注意此時資料是以二進位制的形式進行傳輸。
3. formData有一個append方法,可以新增引數。formData.append("id", "1111");
4. 這種方式只能以post形式傳遞,不需要設定請求頭,瀏覽器會自動為我們設定一個合適的請求頭。
複製程式碼

程式碼示例:

//1. 使用formData必須傳送post請求
    xhr.open("post", "02-formData.php");
    
//2. 獲取表單元素
var form = document.querySelector("#myForm");
//3. 建立form物件,可以直接作為send的引數。
var formData = new FormData(form);

//4. formData可以使用append方法新增引數
formData.append("id", "1111");

//5. 傳送,不需要指定請求頭,瀏覽器會自動選擇合適的請求頭
xhr.send(formData);
複製程式碼

檔案上傳

以前,檔案上傳需要藉助表單進行上傳,但是表單上傳是同步的,也就是說檔案上傳時,頁面需要提交和重新整理,使用者體驗不友好,xhr2.0中的formData物件支援檔案的非同步上傳。

var formData = new FormData();
//獲取上傳的檔案,傳遞到後端
var file = document.getElementById("file").files[0];
formData.append("file", file);
xhr.send(formData);
複製程式碼

顯示檔案進度資訊

xhr2.0還支援獲取上傳檔案的進度資訊,因此我們可以根據進度資訊可以實時的顯示檔案的上傳進度。

1. 需要註冊 xhr.upload.onprogress = function(e){} 事件,用於監聽檔案上傳的進度.注意:需要在send之前註冊。
2. 上傳的進度資訊會儲存事件物件e中
3. e.loaded表示已上傳的大小   e.total表示整個檔案的大小
複製程式碼

程式碼參考:

xhr.upload.onprogress = function (e) {
  
  inner.style.width = (e.loaded/e.total*100).toFixed(2)+"%";
  span.innerHTML = (e.loaded/e.total*100).toFixed(2)+"%";
}

xhr.send(formData);
複製程式碼

如果上傳檔案超過8M,php會報錯,需要進行設定,允許php上傳大檔案。

跨域資源共享(CORS) ( 相容性IE10+ )

cors的使用

新版本的XMLHttpRequest物件,可以向不同域名的伺服器發出HTTP請求。這叫做"跨域資源共享"(Cross-origin resource sharing,簡稱CORS)。

跨域資源共享(CORS)的前提

  • 瀏覽器支援這個功能( 相容性IE10+ )
  • 伺服器必須允許這種跨域。

伺服器允許跨域的程式碼:

//允許所有的域名訪問這個介面
header("Access-Control-Allow-Origin:*");
//允許www.study.com這個域名訪問這個介面
header("Access-Control-Allow-Origin:http://www.study.com");
複製程式碼

CORS的具體流程(瞭解)

  1. 瀏覽器傳送跨域請求

  2. 伺服器端收到一個跨域請求後,在響應頭中新增Access-Control-Allow-Origin Header資源許可權配置。傳送響應

  3. 瀏覽器收到響應後,檢視是否設定了header('Access-Control-Allow-Origin:請求源域名或者*');

    如果當前域已經得到授權,則將結果返回給JavaScript。否則瀏覽器忽略此次響應。

結論:

  1. 跨域行為是瀏覽器行為,響應式回來了的, 只是瀏覽器安全機制做了限制, 對於跨域響應內容進行了忽略。
  2. 伺服器與伺服器之間是不存在跨域的問題的

jsonp與cors的對比

  • jsonp相容性好,老版本瀏覽器也支援,但是jsonp僅支援get請求,傳送的資料量有限。使用麻煩
  • cors需要瀏覽器支援cors功能才行。但是使用簡單,只要服務端設定允許跨域,對於客戶端來說,跟普通的get、post請求並沒有什麼區別。
  • 跨域的安全性問題:因為跨域是需要服務端配合控制的 ,也就是說不論jsonp還是cors,如果沒有服務端的允許,瀏覽器是沒法做到跨域的。

其他的跨域手段

以下方式基本不用啊,瞭解即可:

1、頂級域名相同的可以通過domain.name來解決,即同時設定 domain.name = 頂級域名(如example.com) 2、document.domain + iframe 3、window.name + iframe 4、location.hash + iframe 5、window.postMessage()

相關文章