有趣的前端跨域实现方式

933 阅读5分钟

最通俗易懂的跨域解释

跨域问题的由来

官方解释

    1、A网站通过ajax请求访问B网站的数据(即跨域名请求数据)
    2、但是ajax请求只能向自己的服务器发送请求,不能进行跨域访问
       原因不在服务器,而在于浏览器存在同源政策
    3、什么是同源政策?
       同源政策是浏览器为了保护用户信息安全,防止恶意网站窃取数据,只允许ajax请求自己的服务
       器(即ajax访问地址的协议://域名:端口号都与自身服务器相同即为同源)

有趣的理解跨域

现在小明拉着女朋友ajax的手去见小明的妈(A网站),小明现在想与刚认识的女朋友名为ajax结婚,但是小明的妈(A网站)觉得不行,才认识几天就结婚,要么人品不行,要么就是贪图她家的财产,不安全,于是就拒接了小明的女朋友(ajax),问题来了,小明有几种方案?

1、听妈的,不跟ajax结婚,抛弃她,去找其她的女朋友(jsonp)

2、找妈(A网站)的亲戚(B网站),让他来告诉小明妈,这个女朋友不错,可以结婚,妈也同意了(CORS)

3、私奔,直接偷了户口本,去民政局结婚了,绕过小明妈(服务器代理)

JSONP

抛弃ajax,找到了script

script标签为什么不受同源策影响?

script属于静态访问资源,可以这么理解,脚本的来源取决于脚本所嵌入的资源的来源,比如说访问A主机的当前HTML文件中有一个script标签,这个script标签的src属性请求了一个js脚本,因为这个脚本是由A主机的HTML文件的嵌入的script标签发起请求获取的,因此这个脚本的来源是属于A主机的。 www.cnblogs.com/liuarui/p/1…

核心

A网站的客户端代码

1、在客户端全局作用域下定义函数 fn。(此端口为3000)
<script>
	function fn (data) {
		console.log('客户端的fn函数被调用了')
		//访问到B网站返回的数据
		console.log(data);
	}
</script>
2.将非同源服务器端的请求地址写在script标签的src属性中(访问服务器端口为3001的资源)
<script src="http://localhost:3001/better"></script>

B网站的服务器端代码

3.在非同源服务器端的的路由为/test的接口下
app.get('/test', (req, res) => {
	// 服务器返回在A网站客户端定义的全局函数的执行传入参数
	const result = 'fn({name: "张三"})';
	res.send(result);
});

封装jsonp

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

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

使用jsonp获取腾讯天气数据

jsonp({
    url: 'https://wis.qq.com/weather/common',
	data: {
		source: 'pc',
		weather_type: 'forecast_1h',
		province: '四川省',
		city: '成都市'
	},
	success: function (data) {
		consloe.log(data)
	}
})

CORS

找亲戚(B网站)说情,小明妈(A网站)同意ajax请求。

全称为 Cross-originresource sharing,即跨域资源共享,它允许浏览器向跨域服务器发送 Ajax 请求,克服了 Ajax 只能同源使用的限制。

简单来说就是使用原有的ajax直接进行其他网站(B网站)数据的请求,只需要在要请求的网站(B网站)服务器设置响应头,告诉(A网站)可以访问网站的数据

1、A网站通过ajax请求端口为3001的B网站数据(A网站的客户端代码)
ajax({
	type: 'get',
	url: 'http://localhost:3001/cross',
	success: function (data) {
		console.log(data)
	}
})

2、设置B网站服务器的中间件,让指定域名可以访问B网站的数据 (B网站的服务器代码)
// 拦截所有请求
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')
	// 允许客户端发送跨域请求时携带cookie信息
	res.header('Access-Control-Allow-Credentials', true);
	next();
});


服务器代理

私奔,跳过小明妈(A网站的限制)


1、通过访问A服务器的server接口(偷户口本)(A网站客户端)
ajax({
	type: 'get',
	url: 'http://localhost:3000/server',
	success: function (data) {
		console.log(data);
	}
})

2、通过server接口请B网站的数据,并res.send响应该数据给客户端(A网站服务器端)
// 引入向其他服务器端请求数据的模块
// request("url" , (错误信息, 请求, 请求返回的数据)=>{})
const request = require('request');
app.get('/server', (req, res) => {
	request('http://localhost:3001/cross', (err, response, body) => {
		res.send(body);
	})
});

--注意request是node的模块,需要安装引入npm insatll request -save

--有不完善的,或者错误希望各位可以在评论区提出来,一起进步,谢谢! -_-!