概述
Web程序最初的目的就是将信息(数据)放到公共的服务器,让所有网络用户都可以通过浏览器访问。
在此之前,我们可以通过以下几种方式让浏览器发出对服务端的请求,获得服务端的数据:
- 地址栏输入地址,回车,刷新
- 特定元素的 href 或 src 属性
- 表单提交
这些方案都是我们无法通过或者很难通过代码的方式进行编程(对服务端发出请求并且接受服务端返回的响应),如果我们可以通过JavaScript直接发送网络请求,那么Web的可能就会更多,随之能够实现的功能也会更多,至少不再是”单机游戏”。
AJAX( Asynchronous JavaScript and XML ) ,(先前是服务器返回XML,现在返回的是JSON格式,所以实际上该技术是AJAJ) 最早出现在2005年的Google Suggest (就是搜索框下的建议列表),是在浏览器端进行网络编程(发送请求、接收响应)的技术方案,它使我们可以通过JavaScript直接获取服务端最新的内容而不必重新加载页面。让Web更能接近桌面应用的用户体验。
AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
AJAX就是浏览器提供的一套API ,可以通过JavaScript调用,从而实现通过代码控制请求与响应。实现网络编程。能力不够,API来凑。
AJAX发送请求
XMLHttpRequest:
程序必须先调用 XMLHttpRequest 对象的responseText或responseXML来获取服务器响应,再通过DOM操作将服务器响应动态加载到当前页面中。
关于 XMLHttpRequest 最通用的定义是: XMLHttpRequest是一套可以在JavaScript、VBscript、JScript 等脚本语言中使用的API,它通过HTTP协议异步地向服务器发送请求,并获取从服务器返回的响应。
涉及到 ajax 操作的页面“不能”使用文件协议访问。(不能文件的方式访问)
(我放在了phpstudy_pro里www里的域名为ajax.learn 端口为8080的站点里
所以在网址输入ajax.learn:8080/ajax/ajax1.html即可)
// 1.安装浏览器(浏览器相当于用户代理)
// xhr 就类似于浏览器的作用(发送请求接收响应)
var xhr = new XMLHttpRequest();
// 2. 打开浏览器,输入网址
xhr.open('GET', 'time.php');
// 3. 敲回车,开始请求
xhr.send(); //在检查里的network中all可查看向服务器请求回的
oneeadystatechange事件中获取响应内容
// 1.安装浏览器(浏览器相当于用户代理)
// xhr 就类似于浏览器的作用(发送请求接收响应)
var xhr = new XMLHttpRequest();
// 2. 打开浏览器,输入网址
xhr.open('GET', 'time.php');
// 3. 敲回车,开始请求
xhr.send();
// 4. 等待响应
// 因为响应需要时间,所以无法通过返回值的方式返回响应 即不能console.log(xhr.send());
// 因为客户端永远不知道服务端何时才能返回我们需要的响应
// 所以AJAX API采用事件的机制(通知的感觉)
xhr.onreadystatechange = function () {
//这个事件并不是只在响应时触发, 状态改变就触发,(状态改变即创建xhr、open、send)
console.log(1); //所以打印了3个1
console.log(this.readyState); //2 3 4 因为每个状态对应一个数,0代表创建xhr,1代表open。。。 但是由于事件是后触发的,所以没有打印出全部,
//如果需要捕获第一个状态的变化,需要注意代码执行顺序的问题(不要出现来不及的情况)
}
time.php
<?php
echo time();
?>
readyState有五种可能的值:
0 (未初始化): (XMLHttpRequest)对象已经创建,但还没有调用open()方法。
1 (载入):已经调用open() 方法,但尚未发送请求。
2 (载入完成): 请求已经发送完成。
3 (交互):可以接收到部分响应数据。
4 (完成):已经接收到了全部数据,并且连接已经关闭。
// 1.安装浏览器(浏览器相当于用户代理)
// xhr 就类似于浏览器的作用(发送请求接收响应)
var xhr = new XMLHttpRequest();
console.log(xhr.readyState); // => 0 初始化,请求代理对象
// 2. 打开浏览器,输入网址
xhr.open('GET', 'time.php');
console.log(xhr.readyState); // => 1 open方法已经调用,建立一个与服务端特定端口的连接
// 3. 敲回车,开始请求
xhr.send();
// 4. 等待响应
// 因为响应需要时间,所以无法通过返回值的方式返回响应 即不能console.log(xhr.send());
// 因为客户端永远不知道服务端何时才能返回我们需要的响应
// 所以AJAX API采用事件的机制(通知的感觉)
xhr.onreadystatechange = function () {
//这个事件并不是只在响应时触发, 状态改变就触发,(状态改变即创建xhr、open、send)
// console.log(1); //所以打印了3个1
// console.log(this.readyState); //2 3 4
// switch (this.readyState) {
// case 2:
// console.log(this.readyState);
// // => 2 已经接受到了响应报文的响应头,即服务器名称信息等,但没有接受到响应体
// console.log(this.getAllResponseHeaders()); //打印响应头
// break;
// case 3:
// console.log(this.readyState);
// // => 3 正在下载响应报文的响应体,有可能为空、或不完整、或完整。
// break;
// case 4:
// console.log(this.readyState);
// // => 4 响应体下载完成
// break;
// }
if (this.readyState !== 4) return;
//若状态是4,则获取响应的内容
// console.log(this.readyState); //4
console.log(this.responseText); //1618626395 ,即我们请求的time.php中返回的数据
}
onload事件
var xhr = new XMLHttpRequest();
xhr.open('GET', 'time.php');
xhr.send();
// onload是HTML5 中提供的XMLHttpRequest version 2.0定义的,跟上述一样的功能
xhr.onload = function () {
console.log(this.readyState); //4
console.log(this.responseText); //1618630324
}
ajax遵循HTTP协议
var xhr = new XMLHttpRequest();
xhr.open('POST', 'add.php'); //设置请求行
xhr.setRequestHeader('Foo', 'Bar'); //设置一个请求头
// 一定注意 如果请求体是urlencoded格式必须设置这个请求头
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('key1=value1&key2=value2'); //以urlencoded 格式设置请求体
add.php
<?php
var_dump($_POST);
?>
数据接口的概念
users1.php
<?php
// 返回的响应就是一个JSON 内容(返回的就是数据)
// 对于返回数据的地址一般我们称之为接口(形式上是Web信息)
$data = array(
array(
'id' => 1,
'name' => '束文波'
),
array(
'id' => 2,
'name' => '小夏'
),
array(
'id' => 3,
'name' => '米卡'
),
array(
'id' => 4,
'name' => '邢克垒'
)
);
if (empty($_GET['id'])) {
// 没有传ID,则获取全部
// 因为HTTP中约定报文的内容就是字符串,而我们需要传递给客户端的信息是-个有结构的数据
// 这种情况下我们一般采用JSON作为数据格式
$json = json_encode($data);// 格式:[{"id":1,"name":"束文波"},{...}]
echo $json;
} else {
// 传递了ID,只获取一条
foreach ($data as $item) { //循环遍历,
if ($item['id'] != $_GET['id']) continue; //找到对应的id对应的数组
$json = json_encode($item);
echo $json; //在地址栏设id=1,则打印出{"id":1,"name":"\u675f\u6587\u6ce2"} ,其中汉字是Unicode格式
}
}
发送GET请求并传递参数
var xhr = new XMLHttpRequest();
// 这里仍然是使用URL中的问号参数传递数据
xhr.open('GET', 'users.php?id=3'); //users.php在上面 在这里填京东啊,爱奇艺什么的相关数据接口,在下面即可获取内容
xhr.send(null);
xhr.onreadystatechange = function () {
if (this.readyState !== 4) return;
console.log(this.responseText); //{"id":3,"name":"\u7c73\u5361"}
}
发送GET请求并传递参数—小例子
user2.php
<?php
// 返回的响应就是一个JSON 内容(返回的就是数据)
// 对于返回数据的地址一般我们称之为接口(形式上是Web信息)
$data = array(
array(
'id' => 1,
'name' => '束文波',
'age' => 26
),
array(
'id' => 2,
'name' => '小夏',
'age' => 24
),
array(
'id' => 3,
'name' => '米卡',
'age' => 23
),
array(
'id' => 4,
'name' => '邢克垒',
'age' => 29
)
);
if (empty($_GET['id'])) {
// 没有传ID,则获取全部
// 因为HTTP中约定报文的内容就是字符串,而我们需要传递给客户端的信息是-个有结构的数据
// 这种情况下我们一般采用JSON作为数据格式
$json = json_encode($data); // 格式: [{"id":1,"name":"张三"},{...}]
echo $json;
} else {
// 传递了ID,只获取一条
foreach ($data as $item) { //循环遍历,
if ($item['id'] != $_GET['id']) continue; //找到对应的id对应的数组
$json = json_encode($item);
echo $json; //在地址栏设id=1,则打印出{"id":1,"name":"\u675f\u6587\u6ce2"} ,其中汉字是Unicode格式
}
}
实现:点击名字,弹出相应年龄。
<body>
<ul id="list"></ul>
<script>
var listElement = document.getElementById('list');
// 发送请求获取列表数据呈现在页面
var xhr1 = new XMLHttpRequest();
xhr1.open('GET', 'users2.php');
xhr1.send();
xhr1.onreadystatechange = function () {
if (this.readyState !== 4) return;
//使用 JSON.parse() 方法将请求到的 JSON 数据转换为 JavaScript 对象
var data = JSON.parse(this.responseText);
//循环遍历,为每个li注册点击事件
for (var i = 0; i < data.length; i++) {
// 创建多个元素li
var liElement = document.createElement('li');
// 给li标签设置内容为传过来的name的值
liElement.innerHTML = data[i].name;
liElement.id = data[i].id;
// 把li添加到ul中
listElement.appendChild(liElement);
// 为li注册点击事件
listElement.children[i].addEventListener('click', function () {
// 需要再请求个数据,返回本次点击的响应的数据
var xhr2 = new XMLHttpRequest();
// id为本次点击的名字的id
xhr2.open('GET', 'users2.php?id=' + this.id);
xhr2.send();
xhr2.onreadystatechange = function () {
if (this.readyState !== 4) return;
var data2 = JSON.parse(this.responseText);
// 弹出相应名字的年龄
alert(data2.age);
}
})
}
}
</script>
</body>
发送POST请求
POST请求过程中,都是采用请求体承载需要提交的数据。
如:
xhr.send(`username=${username}&password=${password}`);
login.php
<?php
// 接收用户提交的用户名和密码
if (empty($_POST['username']) || empty($_POST['password'])) {
exit('请提交用户名和密码');
}
//校验
$username = $_POST['username'];
$password = $_POST['password'];
if ($username == '蜡笔小新' && $password == 'ilovexiaogege') {
exit('成功登录');
}
exit('用户名或密码错啦');
?>
实现 点击登录按钮,显示加载层,加载完成后,打印结果
<style>
.loading {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgb(128, 125, 125);
opacity: 0.5;
text-align: center;
line-height: 500px;
font-size: 50px;
display: none;
}
.loading::after {
/*::after用来创建一个伪元素,作为已选中元素的最后一个子元素。这个虚拟元素默认是行内元素。 */
content: '加载中...';
color: #fff;
}
</style>
</head>
<body>
<div class="loading" id="loading"></div>
<table border="1">
<tr>
<td>用户名</td>
<td><input type="text" name="" id="username"></td>
</tr>
<tr>
<td>密码</td>
<td><input type="password" name="" id="password"></td>
</tr>
<tr>
<td></td>
<td><button id="btn">登录</button></td>
</tr>
</table>
<script>
var btn = document.getElementById('btn');
var txtUsername = document.getElementById('username');
var txtPassword = document.getElementById('password');
var loading = document.getElementById('loading');
// 找一个合适的时机,做一件合适的事情
btn.onclick = function () {
//点击登录显示加载中。。。
loading.style.display = 'block';
// 1.获取界面上的元素 value
var username = txtUsername.value;
var password = txtPassword.value;
// 2.通过 XHR 发送一个 POST 请求
var xhr = new XMLHttpRequest();
xhr.open('POST', 'login.php');
// 一定注意 如果请求体是urlencoded格式必须设置这个请求头
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(`username=${username}&password=${password}`);
// 3.根据服务端的反馈 做出界面提示
xhr.onreadystatechange = function () {
if (this.readyState !== 4) return;
//加载完成
loading.style.display = 'none';
console.log(this.responseText); // 用户名或密码错啦
}
}
</script>
</body>
同步与异步
同步:一个人在同一个时刻只能做一件事情,在执行一些耗时的操作 ( 需要看管)不去做别的只是等待
异步:在执行一些耗时的操作(不需要看管)去做别的事,而不是等待
一般很少用同步。
//异步
console.time('aa');
var xhr = new XMLHttpRequest();
// open 方法的第三个参数是async异步 可以传入一个布尔值, 默认为true
xhr.open('GET', 'time.php', true);
xhr.send();
console.log(xhr.responseText); // 为空 此时还未获取到完整数据
// 所以需要:xhr.onreadystatechange = function () 获得完整数据
console.timeEnd('aa'); // aa: 0.64208984375 ms
//同步
console.time('bb');
var xhr2 = new XMLHttpRequest();
// open 方法的第三个参数是async异步 可以传入一个布尔值, 默认为true
xhr2.open('GET', 'time.php', false);
xhr2.send();
// 同步是依次执行,所以不用xhr.onreadystatechange = function () 就能完整接收数据
console.log(xhr2.responseText); // 打印出1618828035
console.timeEnd('bb'); // bb: 21.026123046875 ms
所以很少用到 同步模式。
响应数据格式
XML
一种数据描述手段
老的东西,简单演示一下,基本现在的项目不用。
淘汰的原因:数据冗余太多
JSON
也是一种数据描述手段,类似于JavaScript字面量方式
服务端采用JSON格式返回数据,客户端按照JSON格式解析数据。
不管是JSON也好,还是XML,只是在AJAX请求过程中用到,并不代表它们之间有必然的联系,它们只是数据协议罢了
处理响应数据渲染
模板引擎:
artTemplate : https://aui.github.io/art-template/
模板引擎实际上就是一个API, 模板引擎有很多种,使用方式大同小异,目的为了可以更容易的将数据渲染到HTML中
兼容方案:
XMLHttpRequest在老版本浏览器( IE5/6 )中有兼容问题,可以通过另外一种方式代替
var xhr = window. XMLHttpRequest ? new XMLHttpRequest() : new ActiveXobject(‘Mi crosoft.XMLHTTP’)
<body>
<table>
<tbody id="content"></tbody>
</table>
<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', 'test.php');
xhr.send();
xhr.onreadystatechange = function () {
if (this.readyState !== 4) return;
var res = JSON.parse(this.responseText);
var data = res.data;
for (var i = 0; i < data.length; i++) {
var tr = document.createElement('tr');
var td = document.createElement('td');
//下面方式太麻烦,我们采用模板引擎将数据呈现 artTemplate:https://aui.github.io/art-template/ 模板引擎实际上就是一个API
td.innerHTML = '<td>' + data[i].id + '</td>'
}
}
</script>
</body>
响应类型
this.response 获取到的结果会根据 this.responseType 的变化而变化
this.responseText 永远获取的是字符串形式的响应体
var xhr = new XMLHttpRequest();
xhr.open('GET', 'users2.php');
xhr.send();
xhr.onreadystatechange = function () {
if (this.readyState !== 4) return;
console.log(this);
console.log(this.response == this.responseText); //true
}
若未设置 xhr.responseType = 'json';
则 this.response == this.responseText
若设置:则不相等。
var xhr = new XMLHttpRequest();
xhr.open('GET', 'users2.php');
xhr.send();
xhr.responseType = 'json';
xhr.onreadystatechange = function () {
if (this.readyState !== 4) return;
console.log(this);
}
Ajax 基本的封装
<script>
function ajax(method, url, params, done) {
var res = null;
//若传来的方法是小写,则转化为大写,以便下面判断不出错
method = method.toUpperCase();
var xhr = new XMLHttpRequest();
// 如果params 是个对象,则转换为字符串 {key1:'value1', key2:'value2'}
if (typeof params == 'object') {
var tempArr = [];
for (var key in params) {
var value = params[key];
tempArr.push(key + '=' + value);
} // tempArr => ['key1=value1','key2=value2']
params = tempArr.join('&');
} // params => 'key1=value1&key2=value2'
if (method == 'GET') {
url += '?' + params;
}
xhr.open(method, url);
var data = null;
if (method == 'POST') {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
data = params;
}
xhr.send(data);
xhr.onreadystatechange = function () {
if (this.readyState !== 4) return;
// 不应该在封装函数中主观的处理响应结果
// console.log(this.responseText);
// 无法在内部包含的函数中通过return 给外部函数调用返回结果
// return this.responseText;
// 由于异步模式下,这里的代码最后执行,所以后面res还是=null不等于此结果
// var res = this.responseText;
// 把接收到数据后要做的事情给封装者做
done(this.responseText);
}
}
function onDone(aa) {
console.log(aa);
}
//调用
// params 参数是个字符串
var res = ajax('GET', 'users2.php', 'id=2', onDone); //{"id":2,"name":"\u5c0f\u590f","age":24}
ajax('POST', 'login.php', 'username=蜡笔小新&password=ilovexiaogege', onDone); //成功登录
// params 参数是个对象
ajax('GET', 'users2.php', { id: 2 }, onDone); //{"id":2,"name":"\u5c0f\u590f","age":24}
ajax('POST', 'login.php', {username: '蜡笔小新', password: 'ilovexiaogege'}, onDone); //成功登录
</script>
jQuery中的AJAX
jQuery 中有一套专门针对 AJAX 的封装,功能十分完善,经常使用。
中文文档:https://www.jquery123.com/category/ajax/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script src="jquery-1.11.3/jquery.js"></script>
<script>
// 最基础的调用,最底层的调用
$.ajax('time.php', {
type: 'get', // method 请求方法
success: function (res) { //请求成功则执行函数
// res => 拿到的只是响应体
console.log(res); //1619253401
}
})
// 最常用的调用,最底层的调用
$.ajax({
url: 'users2.php',
type: 'get', // method 请求方法
data: { id: 2 }, // 用于提交到服务端的参数,如果是GET请求就通过url传递
// 如果是POST请求:
// data: `username=${username}&password=${password}`或 data: { username: username, password: password }
dataType: 'json', //当服务端没有设置content-Type时,设此可使得获取的响应体是对象形式,若服务端设content-Type,则此不用写,响应体也是对象形式
//若两者都没有,则是字符串形式
beforeSend: function (xhr) {
// 在所有发送请求的操作(open,send)之前执行
console.log('未请求', xhr);
},
success: function (res) { // 请求成功则执行函数 只有请求成功(状态码为200)才会执行这个函数
// 隐藏loading
// res => 拿到的只是响应体
console.log(res); // {id: 2, name: "小夏", age: 24}
},
error: function (xhr) { //请求不正常
// 隐藏loading
// 只有请求不正常(状态码不为200) 才会执行
console.log('请求失败', xhr);
},
complete: function (xhr) { //请求完成,成功或失败都要执行
console.log('请求完成', xhr);
}
});
// post请求
var username = '蜡笔小新'
var password = 'ilovexiaogege'
$.ajax({
url: 'login.php',
type: 'post', // method 请求方法
data: { username: username, password: password },
// 或 data: `username=${username}&password=${password}`
success: function (res) { // 请求成功则执行函数 只有请求成功(状态码为200)才会执行这个函数
console.log(res); // 成功登录
},
});
</script>
</body>
</html>
jQuery中的快捷方法
// get方法
$.get('users2.php', {id: 4}, function (res) {
console.log(res); // {id: 4, name: "邢克垒", age: 29}
});
var username = '蜡笔小新'
var password = 'ilovexiaogege'
// post方法
$.post('login.php', { username: username, password: password }, function (res) {
console.log(res); // 成功登录
})
// 使用 AJAX 的 HTTP GET 请求获取 JSON 数据
$.getJSON('users2.php', {id: 1}, function (res) {
console.log(res); //{id: 1, name: "束文波", age: 26}
} )
jQuery的 load() 方法
load() 方法通过 AJAX 请求从服务器加载数据,并把返回的数据放置到指定的元素中。
**注释:**还存在一个名为 load 的 jQuery 事件方法。调用哪个,取决于参数。
$(selector).load(url,data,function(response,status,xhr))
例:
使用 AJAX 请求来改变 div 元素的文本
$("button").click(function(){
$("div").load('demo_ajax_load.txt');
});
例子:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>主页面</title>
<link rel="stylesheet" href="../nprogress-master/support/style.css">
<link rel="stylesheet" href="../nprogress-master/nprogress.css">
<style>
.loading {
display: none;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: rgba(0,0,0, .6); /* 写成.6 少零省空间 */
font-size: 30px;
}
</style>
<script src="../nprogress-master/nprogress.js"></script>
</head>
<body>
<!-- 点击链接,在下面只切换main部分,其余不切换。而不用ajax的话,就会整个页面加载切换。 -->
<h1>会员中心</h1>
<hr>
<div class="row">
<aside class="col-md-3">
<div class="list-group">
<a class="list-group-item list-group-item-action" href="index.html">我的资料</a>
<a class="list-group-item list-group-item-action" href="cart.html">我的购物车</a>
<a class="list-group-item list-group-item-action" href="orders.html">我的订单</a>
</div>
</aside>
<main id="main" class="col-md-9">
<h2>姓名:小菜菜。性别:女。电话:1342223442</h2>
<hr>
</main>
</div>
<div class="loading">正在玩命加载中。。。</div>
<script src="../jquery-1.11.3/jquery.js"></script>
<script>
$(function ($) {
//原始的方式--------显示加载进度(暗色 正在玩命加载中。。。
// // 全局事件
// $(document)
// .ajaxStart(function () {
// // 只要有ajax 请求发生就会执行
// $('.loading').fadeIn();
// // 显示加载提示
// console.log('注意要开始请求了');
// })
// .ajaxStop(function () {
// // 只要有ajax 请求结束就会执行
// $('.loading').fadeOut();
// // 结束提示
// console.log('请求结束了');
// })
// 用NProgress库--------显示加载进度 (进度条
$(document)
.ajaxStart(function () {
NProgress.start();
})
.ajaxStop(function () {
NProgress.done();
})
// 有一个独立的作用域,顺便 确保页面加载完成执行
// 当连接被点击,则触发事件,执行 加载相应main部分
$('.list-group-item').on('click', function () {
var url = $(this).attr('href');
// 要插入的远程文档的某个部分.如果该字符串中包含一个或多个空格,紧接第一个空格的字符串则是决定所加载内容的 jQuery 选择器
// 页面只加载了main部分,其余不加载
$('#main').load(url + ' #main > *');
return false;
})
})
</script>
</body>
cart.html
<body>
<main id="main" class="col-md-9">
<h2>小猫猫饼干。简爱牛奶。糖糖。</h2>
<hr>
</main>
</body>
orders.html
<body>
<main id="main" class="col-md-9">
<h2>酸奶块块。茶杯。鼠标垫。</h2>
<hr>
</main>
</body>
同源策略
相关概念:
同源策略是浏览器的一种安全策略,所谓同源是指域名,协议,端口完全相同,只有同源的地址才可以相互通过AJAX的方式请求。
同源或者不同源说的是两个地址之间的关系, 不同源地址之间请求我们称之为跨域请求。
同源策略指的就是:不同源地址之间,默认不能相互发送AJAX请求。
发送跨域请求的方式
同源策略指的就是:不同源地址之间,默认不能相互发送AJAX请求。
当然我们实际应用有时需要跨域请求。
发送跨域请求的方式 . html
<body>
<!-- <script src="../jquery-1.11.3/jquery.js"></script> -->
<script>
// 发送跨域请求的方法:1.能发出去。2.能收回来
// 1. img
// 可以发送不同源地址间的请求,但 不能拿到响应结果。所以不可用 img
// var img = new Image();
// img.src = 'https://wx3.sinaimg.cn/mw690/006qB4OBly1gpy3wwacg4j30j60j6mxx.jpg';
// 2. link
// 可以发送不同源地址间的请求,但 不能拿到响应结果。所以不可用 img
// var link = document.createElement('link');
// link.rel = 'stylesheet';
// link.href = 'https://wx3.sinaimg.cn/mw690/006qB4OBly1gpy3wwacg4j30j60j6mxx.jpg';
// document.body.appendChild(link);
// 3. script
// 可以发送不同源地址间的请求,但 不能拿到响应结果。
// 但是 服务端可以返回js代码,当做js执行,就可拿到响应结果,如下:
var script = document.createElement('script');
script.src = 'http://localhost/time2.php';
document.body.appendChild(script); //开始发起请求,是异步
function foo (res) {
console.log(res);
}
// 请求返回了foo({"time":152242828}),调用foo函数,所以打印出了 {time: 152242828}
</script>
</body>
time2.php
<?php
// 在HTTP协议消息头中,使用Content-Type来表示请求和响应中的媒体类型信息。
header('Content-Type:application/javascript');
// 当客户端 设置 script.src为此服务端时,因为返回的不是js格式而报错,所以不能这样用json
// echo json_encode(array(
// 'time' => time()
// ));
// 所以输出 js 代码
// echo 'var a = {"time":152242828}';
// 在客户端打印出错,因为异步,没请求完就打印了,所以我们调用函数把数据呈现。
// 调用客户端的foo()函数
// echo 'foo({"time":152242828})';
// 当然我们还是要另外的用json
$json = json_encode(array(
'time' => time()
));
echo "foo({$json})";
- JSONP
JSONP的优点就是因为他够老,能兼容各种浏览器,无兼容问题,众生平等。
他发送的不是ajax请求,而是利用了script标签加载机制。他发送的不是ajax请求。
- CORS
CORS从具体的代码实现上来说比较方便,前端几乎不需要写任何代码就可以支持。主要是靠服务端进行配置。而且是对各种请求方法、各种数据请求类型都是完美支持的。
CORS需要浏览器和服务器同时支持。目前所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
JSONP的封装
JSONP的封装.html
<title>JSONP 客户端</title>
</head>
<body>
<script>
function jsonp(url, params, callback) {
// 借助于 script标签发送跨域请求。在客户端借助 script标签请求服务端的一个动态网页( php文件) , 服务端的这个动态网页返回一段带有函数调用的JavaScript
// 全局函数调用的脚本,将原本需要返回给客户端的数据传递进去。
// 为每一个请求创建一个唯一的函数(为防止重名导致出问题)
// 设置随机数
var funcName = 'jsonp_' + Date.now() + Math.random().toString().substr(2, 5);
if (typeof params === 'object') {
var tempArr = [];
for (var key in params) {
var value = params[key];
tempArr.push(key + '=' + value);
}
params = tempArr.join('&');
}
var script = document.createElement('script');
script.src = url + '?' + params + '&callback=' + funcName; // ?callback=' + funcName 是为了告诉服务端需调用的函数名
document.body.appendChild(script);
// 定义funcName函数
// 所有的顶层函数,都可以理解为window的一个方法、[] 跟 . 意义一样
window[funcName] = function (data) {
callback(data);
// 用完后删除
delete window[funcName];
}
}
// 调用
jsonp('http://localhost/server.php', { id: 6 }, function (res) {
console.log(res);
});
</script>
</body>
// 使用jQuery实现 (还是JSONP方法实现跨域,只不过代码在jQuery中封装了下)
<script src="jquery-1.11.3/jquery.js"></script>
<script>
$.ajax({
url: 'http://localhost/server.php',
dataType: 'jsonp',
success: function (res) {
console.log(res);
}
})
</script>
server.php
<?php
// 从数据库拿数据
$conn = mysqli_connect('localhost', 'root', '123456', 'ban');
$query = mysqli_query($conn, 'select * from yan');
while ($row = mysqli_fetch_assoc($query)) {
$data[] = $row;
}
// 判断是否传了函数名
if (empty($_GET['callback'])) {
// 没有就json格式输出在php页面上
header('Content-Type:application/json');
echo json_encode($data);
exit();
}
// 在HTTP协议消息头中,使用Content-Type来表示请求和响应中的媒体类型信息。
header('Content-Type:application/javascript');
$result = json_encode($data);
// 接收函数名
$callback_name = $_GET['callback'];
// echo "ab({$result})"; // 返回js代码 调用ab()函数,此函数在服务端已经定义。 因为是数组,所以用{}
// 返回 js代码--> 调用客户端传来的函数
// //如果$callback_name类型是函数,则输出结果
echo "typeof {$callback_name} === 'function' && {$callback_name}({$result})";
ajax跨域资源共享(CORS)
JSONP是早年跨域请求的方式,我们现在有了 CORS 实现跨域请求。
JSONP的优点 就是因为他够老,能兼容各种浏览器,无兼容问题,众生平等。他发送的不是ajax请求,而是利用了script标签加载机制。他发送的不是ajax请求。
CORS 从具体的代码实现上来说比较方便,前端几乎不需要写任何代码就可以支持。主要是靠服务端进行配置。而且是对各种请求方法、各种数据请求类型都是完美支持的。
CORS需要浏览器和服务器同时支持。目前所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
ajax跨域资源共享(CORS).html
<body>
<script src="jquery-1.11.3/jquery.js"></script>
<script>
// 跨域请求时,客户端不需要做任何设置
// 服务端只需设置 header('Access-Control-Allow-Origin: *');
$.get('http://localhost/cors.php', {}, function (res) {
console.log(res);
})
</script>
</body>
cors.php
<?php
// 从数据库拿数据
$conn = mysqli_connect('localhost', 'root', '123456', 'ban');
$query = mysqli_query($conn, 'select * from yan');
while ($row = mysqli_fetch_assoc($query)) {
$data[] = $row;
}
// 跨域请求时,客户端不需要做任何设置
// 服务端只需设置 header('Access-Control-Allow-Origin: *');
// 一行代码实现跨域
// 允许所有的源对我发起请求
header('Access-Control-Allow-Origin: *');
// 允许某源对我发起请求
// header('Access-Control-Allow-Origin: 具体地址');
header('Content-Type: application/json');
echo json_encode($data);