同源/跨域(nodejs服务器)

如果两个页面拥有相同的协议、域名和端口,那么这两个页面就属于同一个源,其中只要有一个不相同,就是不同源(跨域)

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

1、使用 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 函数内部对服务器端返回的数据进行处理。

    function fn (data) { console.log(data); }
    
JSONP 代码优化
  1. 客户端需要将函数名称传递到服务器端。

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

<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>

对应服务器接口为:

app.get('/better', (req, res) => {
	// 接收客户端传递过来的函数的名称
	const fnName = req.query.callback;
	// 将函数名称对应的函数调用代码返回给客户端
	const data = JSON.stringify({name: "张三"});
	const result = fnName + '('+ data +')';
	 setTimeout(() => {
	 	res.send(result);
	 }, 1000)
});
  1. 封装 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(123)   
       console.log(data) 
      }
})
  1. 服务器端代码优化之 res.jsonp 方法。
   app.get('/better', (req, res) => {
   	// 接收客户端传递过来的函数的名称
   	//const fnName = req.query.callback;
   	// 将函数名称对应的函数调用代码返回给客户端
   	//const data = JSON.stringify({name: "张三"});
   	//const result = fnName + '('+ data +')';
   	// setTimeout(() => {
   	// 	res.send(result);
   	// }, 1000)
   	res.jsonp({name: 'lisi', age: 20});
   });

获取腾讯天气信息案例
腾讯天气接口

url:https://wis.qq.com/weather/common

参数名必选类型说明
sourceStringpc、xw
weather_typeStringForecast_1h 未来48小时 Forecast_24h 未来7天
provinceString省份
citystring城市
日期格式化
		function dateFormat(date) {
			var year = date.substr(0, 4);
			var month = date.substr(4, 2);
			var day = date.substr(6, 2);
			var hour = date.substr(8, 2);
			var minute = date.substr(10, 2);
			var seconds = date.substr(12, 2);
			return year + '年' + month + '月' + day + '日' + hour + '时' + minute + '分' + seconds + '秒';
		}

返回值



    myJsonp017363176455629659({
        "data": {
            "forecast_1h": {
                "0": {
                    "degree": "20",
                    "update_time": "20190529100000",
                    "weather": "多云",
                    "weather_code": "01",
                    "weather_short": "多云",
                    "wind_direction": "西风",
                    "wind_power": "5"
                },
                "1": {
                    "degree": "21",
                    "update_time": "20190529110000",
                    "weather": "多云",
                    "weather_code": "01",
                    "weather_short": "多云",
                    "wind_direction": "西风",
                    "wind_power": "5"
                },
                
            }
        },
        "message": "OK",
        "status": 200
    })



2、CORS 跨域资源共享

CORS:全称为 Cross-originresource sharing,即跨域资源共享,它允许浏览器向跨域服务器发送 Ajax 请求,克服了 Ajax 只能同源使用的限制。
在这里插入图片描述

origin: http://localhost:3000
 Access-Control-Allow-Origin: 'http://localhost:3000'
 Access-Control-Allow-Origin: '*'

Node 服务器端设置响应头示例代码:

 app.use((req, res, next) => {
 	 //也可指定具体的域名信息
 	 //res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
     res.header('Access-Control-Allow-Origin', '*');
     res.header('Access-Control-Allow-Methods', 'GET, POST');
     next();
 })

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

在这里插入图片描述

原理:网站A的客户端访问网站A的服务器,网站A的服务器访问网站B的服务器,从而网站A的服务器获得B网站服务器的响应数据,将数据渲染到A网站的客户端

网站A客户端

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
	<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>
</body>
</html>

网站A服务器端

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

网站B服务器端

app.get('/cross', (req, res) => {
	res.send('ok')
});
withCredentials属性

在使用Ajax技术发送跨域请求时,默认情况下不会在请求中携带cookie信息。

客户端:
withCredentials:指定在涉及到跨域请求时,是否携带cookie信息,默认值为false

// 创建ajax对象
	var xhr = new XMLHttpRequest();
	// 对ajax对象进行配置
	xhr.open('get', 'http://localhost:3001/checkLogin');
	// 当发送跨域请求时,携带cookie信息
	xhr.withCredentials = true;
	// 发送请求并传递请求参数
	xhr.send();
	// 监听服务器端给予的响应内容
	xhr.onload = function () {
		console.log(xhr.responseText);
	}

服务器端:
Access-Control-Allow-Credentials:true 允许客户端发送请求时携带cookie

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();
});
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

陈善强

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

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

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

打赏作者

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

抵扣说明:

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

余额充值