Ajax学习笔记(三)--- 同源政策和跨域解决方案

一、同源政策

​ 什么是同源?如果两个页面拥有相同的协议、域名和端口,那这两个页面就属于同源页面,如果有其中一项不同,就是不同源。

​ 同源政策的目的是为了保证用户的信息安全,防止恶意网站窃取数据。最初的同源政策是指 A 网站在客户端设置的 Cookie,B网站是不能访问的。随着互联网的发展,同源政策也越来越严格,在不同源的情况下,其中有一项规定就是无法向非同源地址发送Ajax 请求,如果请求,浏览器就会报错。

​ 简单来说,就是Ajax 只能向自己的服务器发送请求。比如现在有一个A网站、有一个B网站,A网站中的网页只能向A网站服务器中发送 Ajax 请求,B网站中的网站只能向 B 网站中发送 Ajax 请求,但是 A 网站是不能向 B 网站发送 Ajax请求的,同理,B 网站也不能向 A 网站发送 Ajax请求。

二、跨域解决方案

1、概念

​ 由于同源政策的存在,我们无法访问不同源服务器的数据,称为跨域问题。但在开发时我们很多时候需要访问不同源服务器的数据,因此需要解决跨域问题,使页面能够访问不同的服务器。
为什么跨域是由于浏览器的限制,但解决跨域却都需要服务器的配合呢?因为同源政策还有一个重要目的,就是为了保障服务器的权益,保护其数据隐私,只有得到该不同源服务器的许可,浏览器才能访问到该服务器的数据,类似于保护知识产权。如果没有同源政策的限制,任何人只要拿到了某一服务器的接口地址,就可以发请求获取该服务器的数据,这样就会出大问题。
接下来我们介绍几种常用的解决方案。

2、JSONP 解决方案
概念:

​ jsonp 是 json with padding 的缩写,其实并不属于 ajax 请求,而是利用 script 标签模拟 ajax 请求,只支持get请求,但兼容老版本浏览器。服务器端响应数据必须是一个函数的调用,真正要发送给客户端的数据需要作为函数调用的参数。客户端也要定义全局作用域函数,接收数据,并在函数内部对服务器返回的数据 进行处理

案例代码:
<button id="btn">点我发送请求</button>
	<script>
	// 客户端定义全局作用域函数 内部对服务器返回的数据 进行处理
		function fn2 (data) {
			console.log('客户端的fn函数被调用了')
			console.log(data);
		}
	</script>
	<script type="text/javascript">
		// 获取按钮
		var btn = document.getElementById('btn');
		// 为按钮添加点击事件
		btn.onclick = function () {
			// 创建script标签
			var script = document.createElement('script');
			// 设置src属性
			script.src = 'http://localhost:3001/better?callback=fn2';
			// 将script标签追加到页面中
			document.body.appendChild(script);
			// 为script标签添加onload事件
			script.onload = function () {
				// 将body中的script标签删除掉
				document.body.removeChild(script);
			}
		}
	</script>
封装 jsonp方法:

​ 为了方便 jsonp 的使用,我们将其封装成一个方法,在需要时,直接调用传参即可。

function jsonp (options) {
	// 动态创建script标签
	var script = document.createElement('script');
	// 拼接字符串的变量
	var params = '';

	for (var attr in options.data) {
		params += '&' + attr + '=' + options.data[attr];
	}
	
	// myJsonp0124741
	var fnName = 'myJsonp' + Math.random().toString().replace('.', '');
	// 它已经不是一个全局函数了
	// 我们要想办法将它变成全局函数
	window[fnName] = options.success;
	// 为script标签添加src属性
	script.src = options.url + '?callback=' + fnName + params;
	// 将script标签追加到页面中
	document.body.appendChild(script);
	// 为script标签添加onload事件
	script.onload = function () {
		document.body.removeChild(script);
	}
}


// 调用
jsonp({
	// 请求地址
	url: 'http://localhost:3001/better',
	data: {
		name: 'lisi',
		age: 30
	},
	success: function (data) {
		console.log(456789)
		console.log(data)
	}
})
3、CORS 跨域资源共享
概念:

​ CORS 全称为 Cross-origin resource sharing,即跨域资源共享,它允许浏览器向跨域服务器发送 Ajax 请求,克服了 Ajax 同源政策的限制。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

​ 因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。在服务器拦截所有请求,并设置响应头(Access**-Control-Allow-**Origin)的值。

​ 详细请浏览:http://www.ruanyifeng.com/blog/2016/04/cors.html

案例代码:
// node 服务器端代码
// 拦截所有请求
app.use((req, res, next) => {
	// 1.允许哪些客户端访问我
	// * 代表允许所有的客户端访问我
	// 注意:如果跨域请求中涉及到cookie信息传递,值不可以为*号 比如是具体的域名信息
	res.header('Access-Control-Allow-Origin', 'http://localhost:3000')
	// 2.允许客户端使用哪些请求方法访问我
	res.header('Access-Control-Allow-Methods', 'get,post')
	next();
});

// 浏览器端代码 正常使用 ajax 请求即可
<button id="btn">点我发送请求</button>
	<script src="/js/ajax.js"></script>
	<script>
		// 获取按钮
		var btn = document.getElementById('btn');
		// 为按钮添加点击事件
		btn.onclick = function () {
			ajax({
				type: 'get',
				url: 'http://localhost:3001/cross',
				success: function (data) {
					console.log(data)
				}
			})
		};
	</script>
4、服务器请求转发(反向代理)解决方案
概念:

​ 同源政策是浏览器给予 ajax 技术的限制,不能请求不同源的服务器,但是服务器没有这个限制。所以我们可以通过一个中间的代理服务器,进行请求转发,将客户端的请求转发到真正的目标服务器,此时客户端只知道代理服务器的地址,而不知道目标服务器的地址,代理服务器代理的是目标服务器,所以称为反向代理。
整个过程为:由客户端发起对代理服务器的请求,代理服务器在中间将请求转发给目标服务器,目标服务器将结果返回给代理服务器,代理服务器再将结果返回给客户端。

在这里插入图片描述

案例代码:
// node 服务器代码

// A 服务器
// 向其他服务器端请求数据的模块
const request = require('request');
app.get('/server', (req, res) => {
	request('http://localhost:3001/cross', (err, response, body) => {
		res.send(body);
	})
});
// B服务器
app.get('/cross', (req, res) => {
	res.send('ok')
});

// 前端代码
<button id="btn">点我发送请求</button>
	<script src="/js/ajax.js"></script>
	<script>
		// 获取按钮
		var btn = document.getElementById('btn');
		// 为按钮添加点击事件
		btn.onclick = function () {
			ajax({
				type: 'get',
				url: 'http://localhost:3000/server',
				success: function (data) {
					console.log(data);
				}
			})
		};
	</script>
5、正向代理解决方案

当客户端主动使用代理服务器,向目标服务器发起请求时,此时的代理的是客户端,所以称为正向代理。使用正向代理时,客户端是需要主动配置代理服务的地址、端口、账号密码(如有)等信息才可生效。
常见的正向代理方式有:VPN、梯子、nginx、工程化项目的proxy等。
在这里插入图片描述

三、withCredentials 属性

1、概念

​ 在使用 ajax 技术发送跨域请求时,默认情况下是不会携带 cookie 信息的。而 withCredentials 属性就是用来指定,在请求时是否携带 cookie 信息,默认为 false 。而且需要在服务器段设置 Access-Control-Allow-Credentials 的值为 true ,允许客户端发送请求时携带 cookie。

2、使用
// node 服务器端代码

// 拦截所有请求
app.use((req, res, next) => {
	// 允许客户端发送跨域请求时携带cookie信息
	res.header('Access-Control-Allow-Credentials', true);
	next();
});

// 前端代码

// 为登录按钮添加点击事件
loginBtn.onclick = function () {
	// 将html表单转换为formData表单对象
	var formData = new FormData(loginForm);
	// 创建ajax对象
	var xhr = new XMLHttpRequest();
	// 对ajax对象进行配置
	xhr.open('post', 'http://localhost:3001/login');
	// 当发送跨域请求时,携带cookie信息
	xhr.withCredentials = true;
	// 发送请求并传递请求参数
	xhr.send(formData);
	// 监听服务器端给予的响应内容
	xhr.onload = function () {
		console.log(xhr.responseText);
	}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力的小朱同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值