第五章*****************************************************************************************
AJAX處理數(shù)據(jù)格式application/javascript
問(wèn)題: 一般.js文件中,script請(qǐng)求(任何人)(任何時(shí)間)js內(nèi)容都一樣
解決: 在服務(wù)器端返回"動(dòng)態(tài)js",根據(jù)客戶端不同或訪問(wèn)時(shí)間不同,js也不同
服務(wù)器端:
header("Content-Type:application/javascript;charset=utf-8");
echo "var msg = '你好';alert(msg);"; ? ? ? ? ? ? ? ? ?//msg隨情景不同發(fā)生改變
客戶端:
eval(xhr.responseText); ? ? ? ? ? ? ? ? ?//執(zhí)行php中寫的js程序
_______________________________________________________________________________________________
跨域訪問(wèn)(Cross Domain Request)
瀏覽器的同源策略,出于防范跨站腳本的攻擊,禁止客戶端腳本(如JavaScript)對(duì)不同域(協(xié)議、子域名、主域名protocal、端口port、主機(jī)host)的服務(wù)進(jìn)行跨站調(diào)用
跨域定義:
① 兩個(gè)域名不同 ?a.com → b.com
② 協(xié)議名不同 ? ?http://... → https://...
③ 主機(jī)名/IP不同?http://127.0.0.1/1.php →?http://localhost/2.php
④ 端口號(hào)不同 ? ?http://127.0.0.1:80/1.php →?http://127.0.0.1:8080/2.php
⑤?子域名不同? ? 1.a.com?→ 2.a.com
瀏覽器允許跨域請(qǐng)求的情形: img src="..." / link href="..." / script src="..." / iframe
瀏覽器默認(rèn)禁止XHR(ajax)跨域訪問(wèn)(同級(jí)目錄下除外)———可能會(huì)導(dǎo)致外來(lái)的數(shù)據(jù)對(duì)當(dāng)前程序影響,造成數(shù)據(jù)安全風(fēng)險(xiǎn)
注意: 跨域并不是請(qǐng)求發(fā)不出去,而是請(qǐng)求能發(fā)出去,服務(wù)端能收到請(qǐng)求并正常返回結(jié)果,但結(jié)果被瀏覽器攔截了
三種行為會(huì)受到跨域限制:
①?cookie、localStorage、indexDB
? ?當(dāng)一級(jí)域名相同,二級(jí)域名不同時(shí),可設(shè)置相同的document.domain共享cookie
② DOM無(wú)法獲得
③?ajax請(qǐng)求無(wú)法獲得
方式一 JSONP
解決方案: JSONP?JSON with Padding(填充式JSON)是一種使用JSON數(shù)據(jù)的方法,用于解決瀏覽器xhr跨域請(qǐng)求限制
jsonp思路:
發(fā)起異步請(qǐng)求時(shí)不使用'ajax對(duì)象xhr',而是使用一個(gè)動(dòng)態(tài)創(chuàng)建的 script 標(biāo)簽代替xhr:
? <script async src="跨域訪問(wèn)x.php"></script> ? ? ?? //async:異步
步驟:
① 客戶端:
方法1: ?創(chuàng)建標(biāo)簽→設(shè)置屬性→追加在head中
btn.onclick = function(){
? var script=document.createElement("script");
? script.src="http://127.0.0.1/kuayu/async.php";
? script.async=true; ? ? ? ? ? ? ? ? ? ?//異步請(qǐng)求屬性
? document.head.appendChild(script); ?? //創(chuàng)建一個(gè)script標(biāo)簽,并追加到head中
}
或者:
<script>
function doResponse(data){
? console.log(jsondata); ? ?//處理獲得的json數(shù)據(jù)
}
</script>
<script src="http://127.0.0.1:8090?doResponse=?"></script>
方法2: ?使用dataType:"jsonp"http://jsonp只能是 'GET' 形式,不要寫POST,可能會(huì)報(bào)錯(cuò)
? ? ? ? jQuery封裝好的方法1,會(huì)在head開(kāi)頭插入script標(biāo)簽,響應(yīng)成功后移除
$.ajax({
url:'http://127.0.0.1/web1703/day08/06_jsonp.php',
dataType:"jsonp",//使用JSONP形式調(diào)用函數(shù),標(biāo)志跨域請(qǐng)求
jsonp:'jsonp_callback',//跨域函數(shù)名的鍵值(服務(wù)器提取函數(shù)名的鑰匙,默認(rèn)為callback)
jsonpCallback:'doRespons',//客戶端與服務(wù)端約定的函數(shù)名,取代jQuery自動(dòng)生成的隨機(jī)函數(shù)名
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //若服務(wù)器已設(shè)置jsonp屬性,則不需要再設(shè)置此屬性(此值用來(lái)替代GET或POST請(qǐng)求中URL參數(shù)里的"callback=?"部分,并傳給服務(wù)器)
? success:function(res){},? ? //若設(shè)置jsonpCallback屬性,則執(zhí)行success函數(shù),不執(zhí)行error函數(shù)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //否則相反
? error:function(err){}
});
② 創(chuàng)建函數(shù),接收參數(shù)(設(shè)置jsonpCallback后可省略)
function doResponse(res){? ? ?//創(chuàng)建函數(shù),用來(lái)接收服務(wù)器響應(yīng)數(shù)據(jù)data
? console.log(res);
}
③ 服務(wù)器:
<?php
header("Content-Type:application/javascript;charset=utf-8"); ? ?//向客戶端發(fā)送js程序
$json='{"ename":"tom"}';
echo?'doResponse('.$json.');';? ? ? ? //拼接json字符串,js函數(shù)收到的參數(shù)就是這個(gè)json字符串
?> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//客戶端接收:doResponse(json),會(huì)執(zhí)行這個(gè)函數(shù)
node中
res.end("callback("+str+")"); ?? //發(fā)送的函數(shù)名要與ajax的jsonpCallback的值一致
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//這個(gè)函數(shù)callback可不寫,會(huì)自動(dòng)接著執(zhí)行ajax的success函數(shù)
jQuery中的jsonp類型,會(huì)創(chuàng)建一個(gè)查詢字符串參數(shù)callback=?,這個(gè)參數(shù)會(huì)加在請(qǐng)求的URL后面,服務(wù)器端應(yīng)當(dāng)在JSON數(shù)據(jù)前加上回調(diào)函數(shù)名,以便完成一個(gè)有效的JSONP請(qǐng)求
如果要指定回調(diào)函數(shù)的參數(shù)名來(lái)取代默認(rèn)的callback,可以通過(guò)設(shè)置$.ajax()的jsonp參數(shù)
當(dāng)從服務(wù)器接收到數(shù)據(jù)時(shí),實(shí)際上是用了<script>標(biāo)簽而不是XMLHttpRequest對(duì)象,$.ajax()不再返回一個(gè)XMLHttpRequest對(duì)象,并且也不會(huì)傳遞事件處理函數(shù),比如beforeSend
方式二 CORS
jsonp只能是get形式,承載的信息量有限,所以信息量較大時(shí)CORS是不二選擇
方法:
后臺(tái)直接開(kāi)啟同源策略的訪問(wèn)限制,在允許被跨域訪問(wèn)的文件頭部加上:
header("Access-Control-Allow-Origin:*");
或者:header("Access-Control-Allow-Origin:http://localhost:63342端口號(hào)");
可限制請(qǐng)求方式: header("Access-Control-Allow-Methods:POST,GET");
CORS需要瀏覽器和服務(wù)器同時(shí)支持。目前IE瀏覽器中IE10及以上才可正常發(fā)送請(qǐng)求,其它瀏覽器都支持
CORS是W3C中一項(xiàng)較新的方案,所以部分瀏覽器還沒(méi)有對(duì)其進(jìn)行支持或者完美支持
CORS在移動(dòng)終端支持的不錯(cuò),可以考慮在移動(dòng)端全面嘗試;PC上有不兼容和沒(méi)有完美支持,所以小心踩坑
瀏覽器將CORS請(qǐng)求分成兩類: ?簡(jiǎn)單請(qǐng)求(simple request)和非簡(jiǎn)單請(qǐng)求(not-so-simple request)
只要同時(shí)滿足以下兩大條件,就屬于簡(jiǎn)單請(qǐng)求:
① 請(qǐng)求方法是這三種方法之一:? HEAD、GET、POST
② HTTP的頭信息不超出這幾種字段:? Accept、Accept-Language、Content-Language、Last-Event-ID
? ?Content-Type只限于三個(gè)值: ?application/x-www-form-urlencoded
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? multipart/form-data ? ? ? ?text/plain
凡是不同時(shí)滿足上面兩個(gè)條件,就屬于非簡(jiǎn)單請(qǐng)求
對(duì)于簡(jiǎn)單請(qǐng)求,瀏覽器直接發(fā)出CORS請(qǐng)求。就是在頭信息之中,增加一個(gè)Origin字段
非簡(jiǎn)單請(qǐng)求是那種對(duì)服務(wù)器有特殊要求的請(qǐng)求,比如請(qǐng)求方法是PUT或DELETE,或者Content-Type字段的類型是application/json
CORS定義一種跨域訪問(wèn)的機(jī)制,可以讓AJAX實(shí)現(xiàn)跨域訪問(wèn)。CORS 允許一個(gè)域上的網(wǎng)絡(luò)應(yīng)用向另一個(gè)域提交跨域 Ajax?請(qǐng)求。實(shí)現(xiàn)此功能只需由服務(wù)器發(fā)送一個(gè)響應(yīng)標(biāo)頭即可
① 客戶端 (與正常請(qǐng)求一致):
btn.onclick = function(){
? var xhr = new XMLHttpRequest();
? xhr.onreadystatechange = function (){
? ? if (xhr.readyState === 4 & xhr.status === 200){
? ? ? var obj=JSON.parse(xhr.responseText); ? ? ? ? ? //將后臺(tái)相應(yīng)的數(shù)據(jù)轉(zhuǎn)換成對(duì)象
? ? ? console.log(obj);
? ? }
? }
? xhr.open("GET", "http://127.0.0.1/z_review/jsonp/cors.php", true);
? xhr.send(null);
}
② 服務(wù)器端:
<?php
header("Access-Control-Allow-Origin:*");? ? ? ? ? ? ?//比正常響應(yīng)多一個(gè)此字段
header("Access-Control-Allow-Origin: http://localhost:63342");? ?//或者只允許特定網(wǎng)址訪問(wèn)
header("Content-Type:application/json;charset=utf-8"); ?? //若不加此段會(huì)返回字符串
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //加上之后會(huì)返回一個(gè)對(duì)象
$json='{"ename":"tom"}';
echo? $json;
?>
Node.js中使用CORS跨域:
①服務(wù)器端:
app.all("*",function(req,res,next){
?res.header("Access-Control-Allow-Origin:*");? ?//添加此字段
?res.header("Access-Control-Allow-Origin","http://localhost:63342");? //只允許特定網(wǎng)址訪問(wèn)
? next();
})
app.get("/kuayu",(req,res)=>{
? console.log(req);
? res.json({ename:"tom"});
})
② 客戶端比同域請(qǐng)求的url多出ip及端口:
btn.onclick = function(){
? var xhr = new XMLHttpRequest();
? xhr.onreadystatechange = function (){
? ? if (xhr.readyState === 4 & xhr.status === 200){
? ? ? var obj=JSON.parse(xhr.responseText); ? ? ?? //將后臺(tái)相應(yīng)的數(shù)據(jù)轉(zhuǎn)換成對(duì)象
? ? ? console.log(obj);
? ? }
? }
xhr.open("GET", "http://127.0.0.1:8080/kuayu", true); ?? //必須加http
? xhr.send(null);
}
方式三、通過(guò)修改document.domain來(lái)跨子域
方式四、使用window.name來(lái)進(jìn)行跨域
方式五、使用HTML5中新引進(jìn)的window.postMessage方法來(lái)跨域傳送數(shù)據(jù)(IE 6/7 不支持)
方式六、nginx反向代理
方式七、使用WebSocket
第六章*****************************************************************************************
XML(java 舊項(xiàng)目)
html: 超文本標(biāo)記語(yǔ)言,所有標(biāo)簽預(yù)定義好: ?h1、h2用于描述一個(gè)網(wǎng)頁(yè)結(jié)構(gòu)
xml: 可擴(kuò)展的標(biāo)簽語(yǔ)言,所有標(biāo)簽都是自定義的,用于描述一段數(shù)據(jù),尤其是復(fù)合數(shù)據(jù)
xml語(yǔ)法: ?XML和HTML用途不同,xml語(yǔ)法更加嚴(yán)格
① xml文檔類型聲明
<?xml version="1.0" encoding="utf-8"?>
② 整遍xml有且只有一個(gè)根元素,比如:? <books></books>
③ 標(biāo)簽有開(kāi)始必須有結(jié)束,開(kāi)始標(biāo)簽與結(jié)束的標(biāo)簽完全相同: ?<book></book>
④ 標(biāo)簽可以嵌套不能交叉:? <book><id><i></i></id></book>是正確的
⑤ 標(biāo)簽可以有任意屬性
服務(wù)器端: 通過(guò)程序xml文檔并且發(fā)送
<?php
header("Content-Type:application/xml;charset=utf-8");
echo "<?xml version='1.0' encoding='utf-8'?>";
echo "<根元素>"; ? ? ? ? ? ? ? ? //在php中輸出時(shí),必須用單引號(hào)或雙引號(hào)括起來(lái)
echo "<name>......</name>";
echo "</根元素>";
?>
客戶端:
使用DOM操作原生AJAX發(fā)送請(qǐng)求xml數(shù)據(jù)
btn1.onclick=function(){
? var xhr = new XMLHttpRequest();
? xhr.onreadystatechange=function(){
? ? if(xhr.readyState===4&&xhr.status===200){
? ? ? var doc=xhr.responseXML;
? ? }
? }
? xhr.open('get','xml.php',true);
? xhr.send(null);
}
使用jQuery操作AJAX發(fā)送請(qǐng)求數(shù)據(jù)
btn2.onclick=function(){
? $.ajax({
? ? type:"get",
? ? url:"xml.php",
? ?dataType:"xml",? ? ? ? ? ?//指定服務(wù)器返回類型
? ? success:function(data){...}
? });
}
處理XML數(shù)據(jù)的方法:
① data.documentElement.getElementsByTagName("row") ? ? ? ?//使用原生DOM訪問(wèn)XML數(shù)據(jù)
② $(data).find("row") ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //使用jQuery訪問(wèn)XML數(shù)據(jù)
可以使用操作DOM的方式訪問(wèn)XML的標(biāo)簽、屬性、值
? ?$(res).find("p").each(function(){ console.log($(this).attr('id')) })
第七章*****************************************************************************************
Cookie
作用: 保存(指定保存時(shí)間)用戶添加的數(shù)據(jù),默認(rèn)情況會(huì)話結(jié)束數(shù)據(jù)就刪除了(一般是服務(wù)器使用)
會(huì)話: 是一個(gè)操作過(guò)程,當(dāng)用戶打開(kāi)瀏覽器請(qǐng)求指定頁(yè)面(會(huì)話開(kāi)始),進(jìn)行操作,最后關(guān)閉瀏覽器(會(huì)話結(jié)束)
特點(diǎn):
① 可以自動(dòng)在瀏覽器端和服務(wù)器端來(lái)回傳遞,存儲(chǔ)量約4k,所以不要將不必要的數(shù)據(jù)放到Cookie中
②?可以設(shè)置過(guò)期時(shí)間,超出時(shí)間后,自動(dòng)消失
操作方式
① 保存數(shù)據(jù)至cookie(保存cookie的頁(yè)面):
document.cookie='uid='+uid;
document.cookie="uname="+uname; ? ? ? ? ?? //不會(huì)覆蓋除uname的值
② 從cookie中獲取數(shù)據(jù)(調(diào)用cookie的頁(yè)面):
var cookieArray=document.cookie.split("; ");
var cookieObj={};
? for(var i=0;i<cookieArray.length;i++){
? ? var sub=cookieArray[i].split("=");
? ? var key=sub[0];
? ? var val=sub[1];
? ? cookieObj[key]=val;
? }
if(!cookieObj.uid){
? location.href="輸入cookie內(nèi)容的頁(yè)面";
}
修改cookie過(guò)期時(shí)間
var now = new Date();
now.setFullYear(now.getFullYear()+1);
設(shè)置為一年后過(guò)期:
document.cookie = 'answer='+JSON.stringify(cookieObj.answer)+'; expires='+now.toGMTString();
設(shè)置為永遠(yuǎn)不過(guò)期:
document.cookie = 'answer='+JSON.stringify(cookieObj.answer)+'; expires=Fri, 31 Dec 9999 23:59:59 GMT';
設(shè)置cookie路徑:?document.cookie = "name=value; path=/";
注意事項(xiàng): cookie數(shù)據(jù)保存在客戶端瀏覽器中,不要將安全性高數(shù)據(jù)保存在cookie
cookie保存數(shù)據(jù)通常是: 用戶編號(hào)/用戶喜歡產(chǎn)品編號(hào)/昵稱
XSS(跨站腳本攻擊)是指攻擊者在返回的HTML中嵌入javascript腳本,為了減輕這些攻擊,需要在HTTP頭部配上set-cookie:
httponly? 這個(gè)屬性可以防止XSS,它會(huì)禁止javascript腳本來(lái)訪問(wèn)cookie
secure? ? 這個(gè)屬性告訴瀏覽器僅在請(qǐng)求為https的時(shí)候發(fā)送cookie