解决Ajax同源政策的方法【JSONP + CORS + 服务器端解决方案】


解决Ajax同源政策的方法

使用JSONP解决同源限制问题

jsonp是json with padding的缩写,它不属于Ajax请求,但它可以模以Ajax请求。\

步骤

1.将不同源的服务器端请求地址写在script标签的src属性中

	
		

2.服务器端响应数据必须是一个函数的调用,真正要发送给客户端的数据需要作为函数调用的参数。

const data = 'fn({name: 'lvhang', age: '23'})'
	res.send();

3.在客户端全局作用域下定义函数fn]【这个函数必须定义在script标签的前面!】

	function fn (data) {}

4.在fn函数内部对服务器端返回的数据进行处理

function fn (data) {
	console.log(data)
}

实际上JSONP的核心就是利用script标签可以向非同源的服务器发送请求的特性!在服务器端返回函数调用的代码!

实际测试

  1. 第一步:还是得需要有两个不同源的服务器并开启!【我这里的一号服务器是端口为3003的, 二号是端口为3001的!】

  2. 第二步:你还是在二号服务器上写一个测试路由

  3. 第三步:在一号服务器这儿的lvhang文件夹下新建一个html文件!名字随便起【好歹让他有意义吧!】




	
	
	Document


	
		
		
	


  1. 第四步:在浏览器中查看效果!

看到上面的代码,说明我们已经成功的获取到了不同源的下信息了!

JSONP代码的核心优化!

1.客户端需要将函数名称传递到服务器端。

一号服务器的优化前后代码对比:

  • 优化前:
	
		
		
	
  • 优化后:

		
		
	

二号服务器的代码变化:

// 在二号服务器的app.js中写一个测试路由!让第一个同源来访问!
app.get('/test', (req, res) => {
	// 要在这儿返回一个函数调用的代码!
	const result = 'fn({name: "lvhang"}, {test: "如果你能看到这条消息,说明你已经解决了同源的问题!你用的或许是jsonph or CROS但是,这已经不重要了!"})';
	res.send(result)
})

app.get('/better', (req, res) => {
	// 接收客户端传递过来的函数名称
	const fnName = req.query.callback;
	// 将函数名称对应的函数调用代码返回给客户端!
	const result = fnName + '({name: "lvhang"}, {test: "如果你能看到这条消息,说明你已经解决了同源的问题!你用的或许是jsonph or CROS但是,这已经不重要了!"})';
	res.send(result)
})

2.将script请求的发送变成动态请求。

一号服务器的优化前后代码对比:

  • 优化前:

		
		
	
  • 优化后:

	
		
		
	
	

最主要的区别就是我们可以控制什么时候发送非同源的请求了!动态的发送请求!

实现非同源请求的第二种方法!CORS

CORS 跨域资源共享

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

以下图片来自黑马程序员2019前端

get和post设置在响应头当中!

他和JSONP的不同就是它可以使用原生的Ajax代码实现跨域请求!

1在一号服务器写下常规的Ajax请求的代码!连封装都没有封装过的那种,以示原生的力量!


	

在二号服务器这里写如下的路由

app.get('/cross', (req, res) => {

	// 允许哪些客户端访问我!
	// 第一个参数就是响应头的属性名称
	// 第二个参数就是响应头的属性名称对应的值!
	// * 代表允许所有的客户端访问我!
	res.header('Access-Control-Allow-Origin', '*')
	// 允许客户端使用哪些请求方法访问我!
	res.header('Access-Control-Allow-Methods', 'get, post')

	res.send('您成功的使用CROS跨域资源共享的方法解决了同源的问题!')
})

这样就可以实现跨域访问了!!!!!!=但是这儿有一个严重的问题!就是这还只是一个路由, 那不止一个呢?!所以为了提高效率,我们应该在服务器代码中加入拦截请求, 为所有的请求加上响应头, 这样就不用为每一个路由分别配置跨域访问的代码了!!

app.get('/cross', (req, res) => {

	// 允许哪些客户端访问我!
	// 第一个参数就是响应头的属性名称
	// 第二个参数就是响应头的属性名称对应的值!
	// * 代表允许所有的客户端访问我!
	// res.header('Access-Control-Allow-Origin', '*')
	// 允许客户端使用哪些请求方法访问我!
	// res.header('Access-Control-Allow-Methods', 'get, post')

	res.send('您成功的使用CROS跨域资源共享的方法解决了同源的问题!')

})

// 拦截所有的请求为他们加上响应头!
// next 控制权函数
app.use(function (req, res, next) {
	// 允许哪些客户端访问我!
	// 第一个参数就是响应头的属性名称
	// 第二个参数就是响应头的属性名称对应的值!
	// * 代表允许所有的客户端访问我!
	res.header('Access-Control-Allow-Origin', '*')
	// 允许客户端使用哪些请求方法访问我!
	res.header('Access-Control-Allow-Methods', 'get, post')
	next();
})

访问非同源数据 服务器端解决方案

同源政策是浏览器给予Ajax技术的限制,服务器端是不存在同源攻策限制。

一号服务器html文件中的代码没有变化 如下:

	
	

一号服务器端的代码变化蛮大的!如下:

引入了一个新的模块 request【这个模块要用npm下载偶!】

// 引用request模块! 返回一个request函数
// 向其他服务器端请求数据的模块!服务器端是不受同源政策的影响的!
const request = require('request');

app.get('/server', (req, res) => {
	// 第一个参数请求地址
	// 第二个参数是回调函数!
	// 有三个参数 1 err 错误对象
	// 2 response 服务器端的一些响应信息!
	// 3 body 就是我们需要的信息!
	request('http://localhost:3001/cross', (err, response, body) => {
		console.log(body)
		res.send(body)
	})
})

二号服务端的代码没有变化!

app.get('/cross', (req, res) => {

	// 允许哪些客户端访问我!
	// 第一个参数就是响应头的属性名称
	// 第二个参数就是响应头的属性名称对应的值!
	// * 代表允许所有的客户端访问我!
	// res.header('Access-Control-Allow-Origin', '*')
	// 允许客户端使用哪些请求方法访问我!
	// res.header('Access-Control-Allow-Methods', 'get, post')

	res.send('您成功的使用CROS跨域资源共享的方法解决了同源的问题!')

})