客戶端與服務器的鏈接請參考https://juejin.im/post/5d8088c7e51d453b39774443javascript
async javascript and xml : 異步的JS和XML;html
此處的異步指的是:局部刷新(對應的是全局刷新);java
XML : 可擴展的標記語言,用本身定義的標籤來存儲數據的ajax
在很早之前,咱們基於AJAX和服務器進行交互的數據格式通常都是以XML格式爲主,由於它可以清晰的展現出對應的數據和結構層級;編程
但後來隨着JSON數據格式的到來, 它不只比XML更清晰展現數據的結構,並且一樣的數據存儲,JSON更加輕量,也方便解析和相關的操做,因此如今先後端的數據交互都以JSON格式數據爲主;json
// ===XML===
![](https://user-gold-cdn.xitu.io/2019/9/17/16d3de27498ce477?w=1486&h=716&f=png&s=368962)
<?xml version="1.0" encoding="UTF-8"?>
<root> <student> <name>張三</name> <age>25</age> <score> <english>95</english> </score> </student> <student> <name>張三</name> <age>25</age> </student> <student> <name>張三</name> <age>25</age> </student> </root>
//===JSON===
[{
"name": "張三",
"age": 25,
"score": {
"english": 95
}
}, {
"name": "張三",
"age": 25
}, {
"name": "張三",
"age": 25
}]
複製代碼
那咱們接下來先來看看所有刷新和局部刷新後端
1.全局刷新api
2.局部刷新 跨域
3.當代項目開發的整個架構模型瀏覽器
let xhr = new XMLHttpRequest;
// IE低版本瀏覽器中用的是new ActiveXObject(),
能夠看看高程中JS惰性編程思想,關於XHR的兼容處理;
複製代碼
* method: HTTP請求方式
* url: 請求地址(API接口地址)
* async : 設置同步或者異步,默認是TRUE異步,FALSE同步
* user-name: 傳遞給服務器的用戶名;
* user-pass: 傳遞給服務器的密碼;
xhr.open('GET','./json/xxx.json',true); // 默認異步
複製代碼
// 監聽AJAX的狀態,在狀態爲xxx的時候,獲取服務器響應的內容;
// AJAX狀態碼:0 1 2 3 4
// 當HTTP狀態碼爲2或者3開頭,而且AJAX狀態碼爲4時,獲取響應內容;
xhr.onreadystatechange=function(){
if(xhr.readyState===4 && /^(2|3)\d{2}$/.test(xhr.status)){
let result = xhr.responseText; // =>響應內容
}
}
=> AJAX 狀態碼
`xhr.readyState` 獲取狀態碼
* unsend 0 :未發送(建立一個XHR,初始狀態是0)
* opend 1 : 已經打開(執行了xhr.open);
* headers_received 2 : 響應頭信息 已經返回給客戶端(發送請求後,服務器會一次返回響應頭和響應主體的信息)
* loading 3 :等待服務器返回響應內容
* done 4: 響應主體信息已經返回給客戶端
複製代碼
send中放的是請求主體的內容;
//SEND中放的是請求主體的內容
xhr.send(null);
複製代碼
AJAX任務:發送一個請求給服務器,從服務器獲取到對應的內容,從send後開始,到xhr.readystate === 4 的時候算任務結束;
=> 真實項目中用對應的請求方式,會使請求變得更加明確(語義化),不遵循這些方式也能夠,最起碼瀏覽器在語法上是容許的;可是這些是開發者們相互約定俗稱的規範
GET系列通常用於從服務器獲取信息,POST系列通常用於給服務器推送信息,可是不論GET和POST均可以把信息傳遞給服務器,也能從服務器獲取到結果,只不過是誰多誰少的問題
客戶端怎麼把信息傳遞給服務器?
服務器怎麼把信息返回給客戶端?
GET系列傳遞給服務器信息的方式通常採用:問號傳參 POST系列傳遞給服務器信息的方式通常採用:設置請求主體
1.GET傳遞給服務器的內容比POST少,由於URL有最長大小限制(IE通常限制2KB,其他瀏覽器通常限制4-8K,超過長度的部分自動被瀏覽器截取了)
xhr.open('GET','/list?name=lanlan&age=17...');
xhr.send('...') // 請求主體中傳遞的內容理論上沒有大小限制,
// 可是真實項目中,爲了保證傳輸的速度,咱們會本身限制一些
複製代碼
2.GET會產生緩存(緩存不是本身可控制的),由於請求的地址(尤爲是問號傳參的信息同樣),瀏覽器有時候會認爲你要和上次請求的數據同樣,拿的是上一次信息; 這種緩存咱們不指望有,咱們指望的緩存是本身可控的,因此真實項目中,若是一個地址,GET請求屢次,咱們要去除這個緩存
xhr.open('GET','/list?name=lanlan&age=17...');
xhr.open('GET','/list?name=lanlan&age=17...');
**解決辦法設置隨機數或者時間戳**
xhr.open('GET','/list?name=lanlan&age=17...'+Math.random());
xhr.open('GET','/list?name=lanlan&age=17...'+Math.random());
複製代碼
3.GET相比較POST來講不安全: GET是基於問號傳參傳遞給服務器內容,有一種技術叫作URL劫持,這樣別人能夠獲取或者篡改傳遞信息;而POST基於請求主體傳遞信息,不容易被劫持;
xhr.response / xhr.responseText / xhr.responseXML
xhr.status / xhr.statusText
xhr.timeout
xhr.withCredentials
xhr.abort()
xhr.getAllResponseHeaders()
xhr.getResponseHeader([key])
xhr.open()
xhr.overrideMimeType()
xhr.send()
xhr.setRequestHeader()
一些簡單方法的使用;
let xhr = new XMLHttpRequest;
console.log(xhr.readyState); //=>0
xhr.open('GET', 'json/data.json');
// console.log(xhr.readyState); //=>1
xhr.onreadystatechange = function () {
// console.log(xhr.readyState); //=>2 3 4
if (!/^(2|3)\d{2}$/.test(xhr.status)) return;
if (xhr.readyState === 2) {
//=>獲取響應頭信息
//獲取的服務器時間是標準的日期格式對象(GMT格林尼治時間)
//new Date()能把格林尼治時間轉換爲北京時間
let serverTime = xhr.getResponseHeader('Date');
// console.log(new Date(serverTime));
}
if (xhr.readyState === 4) {
//=>獲取響應主體信息:咱們通常用responseText,由於服務器返回的信息通常都是JSON格式的字符串,若是返回的是XML格式,咱們用responseXML...
// xhr.responseXML
// xhr.response
// xhr.responseType
// console.log(xhr.responseText);
}
}
xhr.send(null);
// ====setTimeout===
let xhr = new XMLHttpRequest;
xhr.timeout = 1; //=>設置AJAX等待時間,超過這個時間算AJAX延遲
xhr.ontimeout = function () {
console.log('請求超時~~'); //若是超過期間就會輸出;
xhr.abort(); //=>手動中斷AJAX的請求
}
xhr.withCredentials = true; //=>在跨域請求中是否容許攜帶證書(攜帶COOKIE)
xhr.open('GET', 'json/data.json');
xhr.send();
// 設置請求頭
let xhr = new XMLHttpRequest;
xhr.open('GET', 'json/data.json');
xhr.setRequestHeader('AAA', '藍藍');
// Uncaught TypeError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': Value is not a valid ByteString. //`設置的請求頭信息值不能是中文 能夠經過encodeURIComponent解碼
xhr.setRequestHeader('AAA', encodeURIComponent('藍藍'));
xhr.onreadystatechange = function () {
if (!/^(2|3)\d{2}$/.test(xhr.status)) return;
if (xhr.readyState === 4) {
console.log(xhr.getRequestHeader);
}
}
xhr.send(null);
複製代碼
//=>AJAX任務的異步
let xhr = new XMLHttpRequest;
xhr.open('GET', 'json/data.json');
//=>設置事件綁定以前狀態1
xhr.onreadystatechange = function () {
console.log(xhr.readyState); //=>2 3 4
}
xhr.send(null);
let xhr = new XMLHttpRequest;
xhr.open('GET', 'json/data.json');
xhr.send(null);
xhr.onreadystatechange = function () {
console.log(xhr.readyState); //=>2 3 4
}
//=>AJAX的同步
let xhr = new XMLHttpRequest;
xhr.open('GET', 'json/data.json', false);
xhr.onreadystatechange = function () {
console.log(xhr.readyState); //=>4 使用AJAX同步編程,不能在狀態碼爲2的時候獲取到響應頭的信息,可是狀態碼爲4的時候也是能夠獲取到頭和主體信息
}
xhr.send(null);
let xhr = new XMLHttpRequest;
xhr.open('GET', 'json/data.json', false);
xhr.send(null);//=>執行後,只有狀態碼爲4纔會繼續處理下面的代碼
//=>狀態碼爲4的時候綁定的,而狀態不會在變了,因此方法不會執行
xhr.onreadystatechange = function () {
console.log(xhr.readyState);
}
複製代碼
/* * $.ajax() 基於原生JS的AJAX四步操做進行封裝 * $.ajax([URL],[OPTIONS]) * $.ajax([OPTIONS]) URL在配置項中(推薦) * $.get/post/getJSON/getScript() * ...... * 配置項信息 * url:請求的API接口地址 * method:HTTP請求方式,默認GET * data:傳遞給服務器的信息,默認null(能夠是字符串,能夠是對象,並且若是GET系列請求,JQ會自動把信息拼接到URL的末尾,基於問號傳參傳遞給服務器;若是是POST請求,JQ會基於請求主體,把信息傳遞給服務器) * dataType:預設服務器返回的結果格式(服務器返回的通常都是JSON格式的字符串,若是咱們設置了DATA-TYPE,JQ會根據設置的類型,把服務器返回的結果處理爲對應的格式),支持的內容text / json / xml / html / script / jsonp(跨域) =>不影響服務器返回的結果,只是把服務器返回的結果進行二次處理 * async:是否爲異步操做,默認是TRUE,表明異步操做 * cache:緩存處理,只對GET系列請求有做用,默認是TRUE不處理緩存,當咱們設置FALSE後,JQ幫咱們在URL的末尾設置一個隨機數 * contentType:設置傳遞給服務器內容的格式類型 默認是"application/x-www-form-urlencoded" * 客戶端傳遞給服務器信息的格式(類型通常都是字符串),經常使用的: * form-data表單數據:JSON格式 '{"name":"xxx","lx":1}' * x-www-form-urlencoded:name=xxx&lx=1 * raw:純文本格式 * headers:設置請求頭信息,他是一個對象 * timeout:設置超時的時間 * success:回調函數,當數據請求成功執行,方法中的參數就是從服務器獲取的結果 * error:回調函數,數據請求失敗執行,方法中的參數是錯誤信息 */
$.ajax({
url: 'http://yapi.demo.qunar.com/mock/95100/project/list',
method: 'POST',
data: {
name: 'lanlan',
lx: 'teacher'
},
dataType: 'json',
async: true,
cache: false,
headers: {},
success: (result, status, xhr) => {
//=>xhr:是JQ幫咱們處理過的AJAX實例
console.log(result, status, xhr);
}
});
複製代碼
<div id="box"></div>
<script>
//new Date()獲取客戶端本地當前時間(不能拿它作重要依據,由於用戶能夠隨意修改)
/* * 倒計時搶購須要從服務器獲取當前時間 AJAX * 問題:時間差(從服務器把時間給客戶端,到客戶端獲取到這個信息,中間經歷的時間就是時間差,而時間差是不可避免的,咱們應儘量減小這個偏差) * - 從響應頭獲取時間(AJAX異步) * - 基於HEAD請求(只獲取響應頭信息) */
let target = new Date('2019/09/14 13:27:00'),
now = null,
timer = null;
//=>從服務器獲取時間:獲取到時間後再作其餘的事情
function func(callback) {
let xhr = new XMLHttpRequest;
xhr.open('HEAD', 'json/data.json', true);
xhr.onreadystatechange = function () {
if (!/^(2|3)\d{2}$/.test(xhr.status)) return;
if (xhr.readyState === 2) { //從響應頭中拿到時間
now = new Date(xhr.getResponseHeader('Date'));
callback && callback();
}
}
xhr.send(null);
}
//=>開啓倒計時模式
function computed() {
let spanTime = target - now;
if (spanTime <= 0) {
//=>到搶購時間:結束定時器
clearInterval(timer);
timer = null;
box.innerHTML = "開搶~~";
return;
}
let hours = Math.floor(spanTime / (60 * 60 * 1000));
spanTime -= hours * 60 * 60 * 1000;
let minutes = Math.floor(spanTime / (60 * 1000));
spanTime -= minutes * 60 * 1000;
let seconds = Math.floor(spanTime / 1000);
box.innerHTML =
`距離搶購還剩 ${hours<10?'0'+hours:hours}:${minutes<10?'0'+minutes:minutes}:${seconds<10?'0'+seconds:seconds}`;
//=>每一次計算完,咱們須要讓NOW在原來的基礎上加上一秒(第一次從服務器獲取到時間,後期直接基於這個時間本身加便可,不要每隔一秒從新從服務器拿)
now = new Date(now.getTime() + 1000);
}
func(() => {
//=>已經從服務器獲取時間了
computed();
timer = setInterval(computed, 1000);
});
</script>
複製代碼