Ajax-跨域-同源政策、Jsonp解決同源限制、CORS跨域資源共享

Ajax請求限制
Ajax 只允許向自己的服務器發送請求。

同源政策

同源:
多個頁面擁有相同的協議域名和端口、否則不同源
多個頁面、多個請求在同一個服務=同源
http和https是不相同的協議

同源政策的目的
同源政策是爲了保證用戶信息的安全,防止惡意的網站竊取數據。最初的同源政策是指A 網站在客戶端設置的 Cookie,B網站是不能訪問的。
因爲同源政策的限制:不允許ajax向不同源服務端發送請求、瀏覽器拒收

JSONP 解決同源限制問題

jsonp 是 json with padding 的縮寫,它不屬於 Ajax 請求,但它可以模擬 Ajax 請求。

步驟

1、將不同源的服務器端請求地址寫在 script 標籤的 src 屬性中。
<script src="www.example.com"></script>
<script src=“https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
2、服務器端響應數據必須是一個函數的調用,真正要發送給客戶端的數據需要作爲函數調用的參數。
 const data = 'fn({name: "張三", age: "20"})';
 res.send(data);
3、在客戶端全局作用域下定義函數 fn。
	//將函數定義在服務器加載的前面
	function fn(data) {
	4、在 fn 函數內部對服務器端返回的數據進行處理。
		console.log('客服端函數被調用');
		console.log(data);	
	  }
//函數必須寫在不同源服務請求的script前面

jsonp優化

1、客戶端需要將函數名稱傳遞到服務器
2、將script請求的發送編程動態請求
3、封裝jsonp函數,方便請求發送
4、動態創建一個script標籤
5、爲script標籤添加src屬性 給封裝函數傳入對象參數
6、將script標籤追加到頁面中
7、在script標籤完成後 把標籤移除
8、因爲發送的函數寫在外面,導致封裝性不好,所以把函數寫在傳遞的參數對象中,需要注意的是在封裝時把函數掛載在window中 使它變成全局的函數,還有一點要注意的是,在多個事件調用函數時前一個事件調用的函數可能會被後面事件調用的函數覆蓋 所以在給函數命名時,使用隨機命名
注意:這不是ajax請求、是模擬ajax
<script type="text/javascript">
		//點擊提交按鈕
 document.getElementById('btn1').onclick = function () {
			//請求非同源服務
			jsonp({
				url: 'http://localhost:3001/better',
				success: function (data) {
					console.log(123);
					console.log(data);

				}
			})
		}
	document.getElementById('btn2').onclick = function () {
			//請求非同源服務
			jsonp({
				url: 'http://localhost:3001/better',
				data:{
					name:'xiaoli',
					age:30
				},
				success: function (data) {
					console.log(1233333);
					console.log(data);

				}
			})
		}
		//封裝 jsonp 函數,方便請求發送
		function jsonp(options) {
			//創建script標籤
			var script = document.createElement('script');
			//準備把參數拼接爲字符串的變量
			var params='';
			//遍歷要傳遞的參數
			for(var attr in options.data){
				//以字符串形式拼接(參數名=參數值、多個參數之間用&隔開)
				params+='&'+attr+'='+options.data[attr];
				//拼接好後把參數放到請求的地址後面
			}
			//定義一個隨機函數、掛載到window下、防止重名覆蓋問題
			var fnName='myJsonp'+Math.random().toString().replace('.','');
			//把fn放入jsonp中、然後讓它變成全局對象
			window[fnName] = options.success;
			//爲script標籤添加src屬性
			script.src = options.url + '?callback='+fnName+params;
			//將script屬性添加到頁面中
			document.body.appendChild(script);
			//標籤創建完後移除
			script.onload = function () {
				document.body.removeChild(script);
			}


		}

	</script>

//服務端代碼優化
app.get('/better', (req, res) => {
	// 接收客戶端傳遞過來的函數的名稱
	//const fnName = req.query.callback;
	// 將函數名稱對應的函數調用代碼返回給客戶端
	//const data = JSON.stringify({name: "張三"});
	//const result = fnName + '('+ data +')';
	// setTimeout(() => {
	// 	res.send(result);
	// }, 1000)
		//express方法
	res.jsonp({name: 'lisi', age: 20});
});


獲取騰訊天氣信息案例

<body>
	<div class="container">
		<table class="table table-striped table-hover" align="center" id="box">

		</table>
	</div>

</body>
<script src="/js/jsonp.js"></script>
<script src="/js/template-web.js"></script>
<script type="text/html" id="tpl">
	<tr>
	<!-- 創建天氣模板、遍歷天氣數據 -->
			<th>時間</th>
			<th>溫度</th>
			<th>天氣</th>
			<th>風向</th>
			<th>風力</th>
		</tr>
		{{each info}}
		<tr>
	<!-- 創建天氣模板、遍歷天氣數據 -->
			<td>{{dateFormat($value.update_time)}}</td>
			<td>{{$value.degree}}</td>
			<td>{{$value.weather}}</td>
			<td>{{$value.wind_direction}}</td>
			<td>{{$value.wind_power}}</td>
		</tr>
		{{/each}}
</script>
<script>
	//獲取父元素
	var box=document.querySelector('#box');
	
       function dateFormat(data){
		 //  console.log(data);
		   
		   //截取年月日、時分秒
			var  year=data.substr(0,4);
			var  month=data.substr(4,2);
			var  day=data.substr(6,2);
			var  hour=data.substr(8,2);
			var  minute=data.substr(10,2);
			var  seconds=data.substr(12,2);
			let time=year+'年'+month+'月'+day+'日'+hour+'時'+minute+'分'+seconds+'秒';
			 return time ;	   
	  }
	//開放一個模板公共變量(必須是函數)
	template.defaults.imports.dateFormat=dateFormat;

	//向非同源服務器獲取天氣信息
	jsonp({
		url: 'https://wis.qq.com/weather/common',
		data: {
			source: 'pc',
			weather_type: 'forecast_1h',
			//多個數據調用
			// weather_type:'forecast_1h|forecast_24h',
			province: 'xx省',
			city: 'xx市'
		},
		success: function (data) {
		//模板拼接
		var html=template('tpl', { info: data.data.forecast_1h });
		console.log(html);
		box.innerHTML=html;
		

		}
	})
</script>

CORS 跨域資源共享

CORS:全稱爲 Cross-originresource sharing,即跨域資源共享,
服務端做配置然後允許瀏覽器向跨域服務器發送 Ajax 請求
在這裏插入圖片描述
請求過程
如果是跨域、客戶端請求是會攜帶origin、服務端請求頭配置了Access-Control-Allow-Origin的話就允許通過同源限制(相當於白名單)

 在服務端設置響應頭
 	// 1.允許哪些客戶端訪問我
	// * 代表允許所有的客戶端訪問我
 	res.header('Access-Control-Allow-Origin', 'http://localhost:3000')
	// 2.允許客戶端使用哪些請求方法訪問我
	res.header('Access-Control-Allow-Methods', 'get,post')
 //一般都設置在攔截所有請求的響應代碼中 記得調用next方法向下傳遞

同源政策是瀏覽器對ajax技術的限制、服務端不存在同源限制

跨服務響應數據
a頁面訪問a服務、a服務訪問b服務、然後在響應回a頁面、
下載request第三方模塊、使用返回的request方法

app.get('/server', (req, res) => {
//a服務訪問b服務
	request('http://localhost:3001/cross', (err, response, body) => {
		res.send(body);
	})
});

cookie
客戶端請求時,服務器響應 並且給客戶端一個唯一的標識

在使用Ajax技術發送跨域請求時,默認情況下不會在請求中攜帶cookie信息

withCredentials://指定在涉及到跨域請求時,是否攜帶cookie信息 默認爲false–客戶端
Access-Control-Allow-Credentials: true//允許客戶端發送請求時攜帶cookie --服務器端

	// 當發送跨域請求時攜帶cookie信息
			 xhr.withCredentials=true;
	// 允許客戶端發送跨域請求時攜帶cookie信息
	res.header('Access-Control-Allow-Credentials', true);
這兩個設置要同時設置 否則不會成功攜帶cookies
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章