跨域---jsonp方式

123 阅读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 代码示例

客户端代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button id="btn">发送请求</button>
    <script>
        function fn(data) {
            console.log('s1函数被调用了');
            console.log(data);
        }
    </script>
    <script>
        var btn = document.getElementById('btn');
        btn.onclick = function() {
            // 动态创建script标签
            var script = document.createElement('script');
            script.src = "http://localhost:3001/test";
            document.body.appendChild(script);
            script.onload = function() {
                document.body.removeChild(script);
            }
        }
    </script>
</body>

</html>

服务器端代码

app.get('/test', (req, res) => {
    // const result = 'fn({name: "张三"})';
    var result = 'fn({name:"张三"})';
    res.send(result)
});

封装jsonp代码函数

创建一个jsonp.js文件,将下列代码粘贴进去(封装好的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文件案例

获取腾讯天气

客户端代码

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>使用jsonp获取腾讯天气信息</title>
	<link rel="stylesheet" href="/assets/bootstrap/dist/css/bootstrap.min.css">
	<style type="text/css">
		.container {
			padding-top: 60px;
		}
	</style>
</head>
<body>
	<div class="container">
		<table class="table table-striped table-hover" align="center" id="box"></table>
	</div>
	<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>
		// 获取table标签
		var box = document.getElementById('box');

		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 + '秒';
		}

		// 向模板中开放外部变量
		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: '黑龙江省',
				city: '哈尔滨市'
			},
			success: function (data) {
				var html = template('tpl', {info: data.data.forecast_1h});
				box.innerHTML = html;
				
			}
		})
	</script>
</body>
</html>
</html>

服务器端代码

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: 'zhangsan',
        age: 18
    })
});