340 跨域:jsonp,jquery对于jsonp的封装,跨域资源共享(CORS)
【演示跨域问题.html】
jsonp
JSONP:JSON with Padding,可用于解决主流浏览器的跨域数据访问的问题。
原理:服务端返回一个预先定义好的javascript函数的调用,并且将服务器的数据以该函数参数的形式传递过来,这个方法需要前后端配合。
script
标签是不受同源策略的限制的,它可以载入任意地方的 JavaScript 文件,而并不要求同源。
类似的还有img
和link
标签。
<!--不受同源策略的标签-->
<script src="http://www.api.com/1.js"></script>
<img src="http://www.api.com/1.jpg" alt="">
<link rel="stylesheet" href="http://www.api.com/1.css">
jsonp演化过程
了解jsonp原理,同时jquery已经帮我们封装好了,我们使用起来非常的方便。
$.ajax({
dataType:'jsonp',
})
dataType:jsonp 即可解决跨域;
jsonp的原理:
在跨域的时候,发送ajax请求会受到浏览器的限制。
在跨域的时候,通过XMLHttpRequest请求服务器会受到浏览器的限制, 在跨域的情况XMLHttpRequest无法成功请求服务器的,就算设置dataType:jsonp 也不行。
其实在跨域情况下,$.ajax方法内部并没有使用XMLHttpRequest对象请求,而是使用其他方式来实现的。
jsonp 和 XMLHttpRequest对象无关!!
在跨域的情况下,$.ajax内部是如何请求服务器?
jsonp本质是使用script的src属性跨域请求的服务器!;
jsonp请求服务器的步骤:
1-前端需要先定好一个方法,利用script将 把方法名传递给后台
2-后台会获取方法名,然后在方法名后面拼接括号,在向括号中填充json数据
3-后台会返回 填充好数据的方法调用,say({"name":"zs", "age":18});
4-前端接受到返回的方法调用,会立即当做js执行,即可获取后台填充参数,进行使用
注意点:
1-jsonp只能发送get请求,jsonp具有get方式优点和缺点
2-jsonp需要前端后配合才能完成
前端:
function say(obj) { }
<script src="01.php?callback=say"></script>
后台:
echo $_GET['callback'].'('{"name":"zs"}')' // say({"name":"zs"});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!--
jsonp本质是使用script的src属性跨域请求的服务器!;
if (dataType=='json') {
} else {
//XMLHttpRequest
}
在跨域的情况下,$.ajax内部是如何请求服务器?
jsonp请求服务器的步骤:
1-前端需要先定好一个方法,利用script将 把方法名传递给后台
2-后台会获取方法名,然后在方法名后面拼接括号,在向括号中填充json数据
3-后台会返回 填充好数据的方法调用 say({"name":"zs", "age":18});
4-前端接受到返回的方法调用,会立即当做js执行, 即可获取后台填充参数,进行使用
-->
<!-- 跨域,能请求图片的 -->
<!-- <img src="https://www.jisuapi.com/static/images/iconv2/aqi.png" alt=""> -->
<!-- 跨域能请求js文件 -->
<!-- <script src="http://www.test.com/11/test/test.js"></script> -->
<!-- 标签src、href 都具备跨域请求资源的能力 -->
<!-- src能跨域请求php程序 -->
<!-- <script src="http://www.test.com/11/test/test.php"></script> -->
<!-- script src 能向后台传递数据 -->
<!-- <script src="http://www.test.com/11/test/test.php?name=zs"></script> -->
<script>
//前端有渲染数据方法,缺数据
function say(obj) {
alert('你好' + obj.name);
}
var obj = {
name: 'zs'
}
</script>
<!-- 利用script标签将方法名传递给后台 -->
<script src="http://www.test.com/11/test/test1.php?callback=say"></script>
</body>
</html>
<?php
// jsonp json with padding 用json数据进行填充
// 后台就是仓库,有的就是数据
$info = [
"name" => "xiaoming",
"age" => 16
];
$info = json_encode($info); // {"name":"xm", "age": 16}
// 'say' . '('. '{"name":"xm", "age": 16}'. ')';
echo $_GET['callback'].'('.$info.')'; // say({"name":"xm", "age": 16});
// echo say({"name":"zs", "age": 18});
// $s1 = 'aaa';
// $s2 = 'bbb';
// $s3 = 'ccc';
// $s4= $s1 . $s2. $s3; // 'aaabbbccc'
//echo say({"name":"xm", "age": 16}); json with padding
?>
jquery对于jsonp的封装
//使用起来相当的简单,跟普通的get请求没有任何的区别,只需要把dataType固定成jsonp即可。
$.ajax({
type:"get",
url:"http://www.api.com/testjs.php",
dataType:"jsonp",
data:{
uname:"hucc",
upass:"123456"
},
success:function (info) {
console.log(info);
}
});
案例:查询天气.html
http://lbsyun.baidu.com/index.php?title=car/api/weather
秘钥:zVo5SStav7IUiVON0kuCogecm87lonOj
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="../table.css">
<style>
img {
width: 60px;
height: 50px;
}
</style>
</head>
<body>
<button>获取添加</button>
<table></table>
<!-- date: "周五 03月15日 (实时:19℃)"
dayPictureUrl: "http://api.map.baidu.com/images/weather/day/duoyun.png"
nightPictureUrl: "http://api.map.baidu.com/images/weather/night/duoyun.png"
temperature: "19 ~ 7℃"
weather: "多云"
wind: "西北风3-4级"
__proto__: Object -->
<script type="text/html" id="tmp">
{{ each list v i }}
<tr>
<td>{{ v.date }}</td>
<td>{{ v.temperature }}</td>
<td>{{ v.weather }}</td>
<td>{{ v.wind }}</td>
<td><img src="{{ v.dayPictureUrl }}" alt=""></td>
<td><img src="{{ v.nightPictureUrl }}" alt=""></td>
</tr>
{{ /each }}
</script>
<script src="../jquery-1.12.4.min.js"></script>
<script src="../template-web.js"></script>
<script>
//1-点击按钮,请求百度的天气预报接口,获取天气数据
// http://api.map.baidu.com/telematics/v3/weather?location=北京&output=json&ak=E4805d16520de693a3fe707cdc962045
//解决跨域使用jsonp
$('button').click(function() {
$.ajax({
type: 'get',
url: 'http://api.map.baidu.com/telematics/v3/weather',
data: {
ak: 'zVo5SStav7IUiVON0kuCogecm87lonOj',
location: '上海',
output: 'json'
},
dataType: 'jsonp', //解决跨域 成功
success: function(info) {
console.log(info.results[0].weather_data);
info = info.results[0].weather_data; //数组
var obj = {
list: info
};
$('table').html(template('tmp', obj)); //绑定数据和模版
}
})
});
$.ajax({
dataType: 'jsonp',
})
</script>
</body>
</html>
案例:省市区三级联动.html
api地址 : https://www.jisuapi.com/api/weather/
appkey: 3fa977031a30ffe1
图灵机器人:http://www.tuling123.com/
跨域资源共享(CORS)
使用jsonp跨域的缺点:
(1)麻烦,需要前后端人员相互配合,双方都要掌握jsonp;
(2)jsonp不能发送大量的数据给后台。
cors的使用
新版本的XMLHttpRequest对象,可以向不同域名的服务器发出HTTP请求。这叫做"跨域资源共享"(Cross-origin resource sharing,简称CORS)。
跨域资源共享(CORS)的前提
- 浏览器支持这个功能
- 服务器必须允许这种跨域。
服务器允许跨域的代码:
//允许所有的域名访问这个接口
header("Access-Control-Allow-Origin:*");
//允许www.study.com这个域名访问这个接口
header("Access-Control-Allow-Origin:http://www.study.com");
CORS的具体流程(了解)
- 浏览器会根据同源策略 查看是否是跨域请求,如果同源,直接发送ajax请求。
- 如果非同源,说明是跨域请求,浏览器会自动发送一条请求(预检请求 ),并不会携带数据,服务器接受到请求之后,会返回请求头信息,浏览器查看返回的响应头信息中是否设置了
header('Access-Control-Allow-Origin:请求源域名或者*');
- 如果没有设置,说明服务器不允许使用cors跨域,那么浏览器不会发送真正的ajax请求。
- 如果返回的响应头中设置了
header('Access-Control-Allow-Origin:请求源域名或者*');
,浏览器会跟请求头中的Origin: http://www.study.com
进行对比,如果满足要求,则发送真正的ajax请求,否则不发送。 - 结论:跨域行为是浏览器行为,是浏览器阻止了ajax行为,服务器与服务器之间是不存在跨域的问题的。
案例:图灵机器人
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Ajax</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #F7F7F7;
}
h3 {
text-align: center;
}
.chatbox {
width: 500px;
height: 500px;
margin: 0 auto;
border: 1px solid #CCC;
background-color: #FFF;
border-radius: 5px;
}
.messages {
height: 350px;
padding: 20px 40px;
box-sizing: border-box;
border-bottom: 1px solid #CCC;
overflow: scroll;
}
.messages h5 {
font-size: 20px;
margin: 10px 0;
}
.messages p {
font-size: 18px;
margin: 0;
}
.self {
text-align: left;
}
.other {
text-align: right;
}
.form {
height: 150px;
}
.form .input {
height: 110px;
padding: 10px;
box-sizing: border-box;
}
.form .btn {
height: 40px;
box-sizing: border-box;
border-top: 1px solid #CCC;
}
.form textarea {
display: block;
width: 100%;
height: 100%;
box-sizing: border-box;
border: none;
resize: none;
outline: none;
font-size: 20px;
}
.form input {
display: block;
width: 100px;
height: 30px;
margin-top: 5px;
margin-right: 20px;
float: right;
}
iframe {
position: absolute;
left: 10px;
top: 10px;
/* border: 1px solid green; */
width: 320px;
height: 600px;
box-shadow: 0 0 10px 0 #333;
}
</style>
</head>
<body>
<h3>简单的Ajax实例</h3>
<div class="chatbox">
<!-- 聊天内容 -->
<div class="messages">
</div>
<!-- 表单 -->
<div class="form">
<!-- 输入框 -->
<div class="input">
<textarea></textarea>
</div>
<!-- 按钮 -->
<div class="btn">
<input type="button" value="发送">
</div>
</div>
</div>
<iframe src="" frameborder="0"></iframe>
<script type="text/template">
<div class="self">
<h5>我说</h5>
<p>你好</p>
</div>
<div class="other">
<h5>对方说</h5>
<p>你好</p>
</div>
</script>
<!-- 小技巧:先写模板,在模板中直接使用一些变量名,这些都是将来传给模板的对象属性 -->
<!-- 准备模板 -->
<script type="text/template" id="tmp">
{{ if flag == 'self'}}
<div class="self">
<h5>我说:</h5>
<p>{{ msg }}</p>
</div>
{{ else }}
<div class="other">
<h5>对方说:</h5>
<p>{{ msg }}</p>
</div>
{{ /if }}
</script>
<script src="../../jquery-1.12.4.min.js"></script>
<!-- 引入模板引擎插件 -->
<script src="../../template-web.js"></script>
<script>
//1-点击按钮,获取输入框中值,添加到聊天窗口
//2-向后台发送请求,等待后他返回聊天内容
//3-将后台返回聊天内容,添加到聊天窗口中
$('.btn input').click(function () {
var txt = $('textarea').val(); //txt只是一个字符串,模板需要数据是对象
// 包装
var data = {
flag: 'self',
msg: txt
}
//组合
var str = template('tmp', data);
$('.messages').append(str);
//清空输入框
$('textarea').val('');
//向后台发送请求,等待后他返回聊天内容
$.ajax({
type: 'post',
url: 'http://www.tuling123.com/openapi/api',
dataType: 'json',
data:{
key:'7e3ff98681194706b84b0338016ed987',
info: txt,
loc: '上海',
userid: '123456'
},
success: function (info) {
console.log(info);
var data = {
flag: 'other',
msg: info.text
}
//生成结构
$('.messages').append( template('tmp', data) );
if (info.url) {
// window.open(info.url);
$('iframe').attr('src', info.url);
}
if (info.list) {
$('iframe').attr('src', info.list[0].detailurl);
}
}
})
})
</script>
</body>
</html>
其他的跨域手段(没卵用)
以下方式基本不用,了解即可:
1、顶级域名相同的可以通过domain.name来解决,即同时设置 domain.name = 顶级域名(如example.com)
2、document.domain + iframe
3、window.name + iframe
4、location.hash + iframe
5、window.postMessage()
虚拟主机配置
在一台web服务器上,我们可以通过配置虚拟主机,然后分别设定根目录,实现对多个网站的管理。
具体步骤如下:
1.找到http.conf文件
找到470行,去掉#
号注释
# Virtual hosts
Include conf/extra/httpd-vhosts.conf
2.找到httpd-vhosts.conf
文件
在目录:D:\phpStudy\Apache\conf\extra下找到httpd-vhosts.conf文件