提示:继续上一节的CSS基础学习,AJAX(Asynchronous JavaScriptandXML)
前言
Ajax不是某种编程语言,是一种在无需重新加载整个网页的情况下能够更新部分网页的技术。改变了Web开发的格局。
传统网页(即不使用Ajax技术的网页),想要更新内容或者提交一个表单,就需要重新载入页面。
使用了Ajax技术的网页,通过在后台跟服务器进行少量的数据交换,网页就可以实现异部局部更新。
AJAX 的优势:
不需要插件的⽀持,原⽣ js 就可以使⽤
⽤户体验好(不需要刷新⻚⾯就可以更新数据)
减轻服务端和带宽的负担
AJAX的劣势:
搜索引擎的⽀持度不够,因为数据都不在⻚⾯上,搜索引擎搜索不到
要学习Ajax,我们需要了解三方面,HTML,JS,CSS
。
提示:以下是本篇文章正文内容,下面案例可供参考
一、Ajax概念介绍
Ajax 全名 async javascript and XML(异步JavaScript和XML),是前后台交互的能⼒,也就是我们客户端给服务端发送消息的⼯具,以及接受响应的⼯具。
Ajax的大致操作流程:
具体操作流程:
-
首先通过PHP页面将数据库中的数据取出;
-
取出之后转成JSON格式的字符串,后利用Ajax把字符串返还给前台;
-
再利用JSON.parse解析通过循环添加到页面上;
-
那么反之,前端数据可以利用Ajax提交到后台;
-
但是后台是没有办法直接把这些数据插入到数据库中,所以要先提交到PHP页面上;
-
最后再 由 PHP将数据插入到数据库中。
1、Ajax-同步和异步
Ajax是⼀个 默认异步
执⾏机制的功能,AJAX分为同步(async = false)和异步(async = true)。
同步请求:
同步请求是指当前发出请求后,浏览器什么都不能做, 必须得等到请求完成返回数据之后,才会执行后续的代码。
相当于生活中的排队,必须等待前一个人完成自己的事,后一个人才能接着办。
举个就更具体的例子,就像我们在网上填写关于自己的个人信息,有很多内容,然后我们提交之后才会发现有几个空没有填,然后我们找来找去,填了哪一个之后,又提交,页面又提示我们没有填写完整。
也就是说,当JS代码加载到当前AJAX的时候会把页面里所有的代码停止加载,页面处于一个假死状态,当这个AJAX执行完毕后才会继续运行其他代码页面解除假死状态。
异步请求:
默认异步:异步请求就当发出请求的同时,浏览器可以继续做任何事,Ajax发送请求并不会影响页面的加载与用户的操作,相当于是在两条线上,各走各的,互不影响。
举个具体的例子,就像我们在网上填写关于自己的个人信息,有很多内容,然后我们在填写的时候,没有填上的会直接提醒。
一般默认值为true,异步。异步请求可以完全不影响用户的体验效果,无论请求的时间长或者短,用户都在专心的操作页面的其他内容,并不会有等待的感觉。
2、Ajax-XMLHttpRequest对象
在 js 中有内置的构造函数来创建 Ajax 对象,创建 Ajax 对象以后,我们就使⽤ Ajax 对象的⽅法去发送请求和接受响应。
Ajax的一个最大的特点是无需刷新页面便可向服务器传输或读写数据(又称无刷新更新页面),这一特点主要得益于XMLHTTP组件XMLHTTPRequest对象。
XMLHttpRequest对象方法描述:
方法 | 描述 |
---|---|
abort() | 停止当前请求 |
getAllResponseHeaders() | 把HTTP请求的所有响应首部作为键/值对返回 |
getAllResponseHeader(“header”) | 返回指定首部的串值 |
open(“method”,“URL”,[asyncFlag],['userName"],[“password”]) | 建立对服务器的调用。method参数可以是GET、post或者PUT。URL参数可以是相对URL或绝对URL。这个方法还包括三个可选参数,是否异步,用户名,密码 |
send(content) | 向服务器发送请求 |
setRequestHeader(“header”,'value") | 把制定首部设置为所提供的值。在设置任何首部之前必须先调用open()。设置header并和请求一起发送(‘post’方法一定要) |
2.1、创建XMLHttpRequest对象
var xhr=new XMLHttpRequest();
//ie7以上
var request;
if(windows.XMLHttpRequest){
request=new XMLHttpRequest();
}else{
request=new ActiveXObject("Microsoft.XMLHTTP");
}
//ie6以下
2.2、Ajax-HTTP请求
之前在博客CTF学习之0基础入门笔记(二)中已经详细解读过,这里稍微再提一下。
HTTP是计算机通过网络进行通信的规则,使我们用户通过浏览器向web服务器请求信息和服务。HTTP是一种无状态(不建立持久联系)协议,也就是服务端不保存建立连接的信息。
一个完整的HTTP请求过程,通常有7个步骤:
1、建立TCP连接
2、Web浏览器向Web服务器发送请求和命令
3、Web浏览器发送请求头信息
4、Web服务器应答
5、Web服务器发送应答头信息
6、Web服务器向浏览器发送数据
7、Web服务器关闭TCP连接
一个HTTP请求一般由四部分组成:
1、HTTP请求的动作或方法,比如是GET或者POST请求
2、正在请求的URL,总得知道请求的地址是什么吧
3、请求头,包含一些客户端换进信息,身份验证信息等
4、请求体,也就是请求正文,请求正文中可以包含客户提交的查询字符串信息,表单信息等等
GET:一般用于信息获取,明文对所有人可见,使用URL传递参数,对所发送信息的数量也有限制,一般在2000个字符。
POST:一般用于修改服务器上的资源,对所发送的信息的数量无限制。
一个HTTP响应一般由三部分组成:
1、一个数字和文字组成的状态码(具体可见CTF学习之0基础入门笔记(二)),用于显示请求是成功还是失败
2、响应头,响应头也和请求头一样包含许多有用的信息,例如服务器类型、日期时间、内容类型和长度等
3、响应体,也就是响应正文
2.3、Ajax-XMLHttpRequest发送请求
1、open(method,url,async)
method:发送请求方法,不区分大小写,一般用大写
url:请求地址,可以是绝对地址,也可以是相对地址
async:代表请求是同步(false)还是异步(ture)
2、send(string)
如果用GET请求,string可以不加参数,或者NULL。
如果是POST请求,string需要填写。
举个例子:
request.open("GET","get.php",true);
request.send();
request.open("POST","post.php",ture);
request.send();
request.open("POST","create.php",ture);
request.setRequestHeader("Content-type","application/x-www-form-urlencoded");
request.send("name=林翠花&sex=男");
2.4、Ajax-XMLHttpRequest获得响应
responseText:获取字符串形式的响应数据
responseXML:获得XML形式的响应数据
status和statusText:以数字和文本形式返回HTTP状态码
getAllResponseHeader():获取所有的响应报头
getResponseHeader():查询响应中的某个字段的值
readyState属性:
0:请求初始化,open还没有调用
1:服务器连接已建立,open已经调用了
2:请求已接收,也就是接收到头信息了
3:请求处理中,也就是接收到响应主体了
4:请求已完成,且响应已就绪,也就是响应完成了
var request=new XMLHttpRequest();//new一下
request.open("GET","get.php",ture);
request.send();//请求
request.onreadystatechange=function(){
if(request.readyState===4&&request.statue===200){//对服务做监听
//做一些事情
request.responseText
}
}
二、Ajax的简单例子(Ajax+PHP)
1、Ajax-例子简介
1、查询员工信息,可以通过输入员工编号查询员工基本信息;
2、新建员工信息,包含员工姓名,员工编号,员工性别,员工职位。
上面这些,我们静态页面可以很好实现,但在这里我们要实现第二个要求,就需要用到了PHP。
首先,纯html页面,用来实现员工查询和新建的页面;
其次,PHP页面,用来实现查询员工和新建员工的后台接口。
1.1、PHP是什么:
PHP是一种创建动态交互性站点的服务器端脚本语言。
像我们知道的HTML、JS使用在客户端,是浏览器的脚本语言,可以做一些页面的呈现和特效,但是我们开发一个网站,我们要在上面存一些东西,这些明显就满足不了我们的需求。
比如我们开发一个新闻站点,站点比较复杂,每个新闻不可能存在我们的电脑里面,这个不太现实,我们需要有一个地方单独去存储,每个用户通过网站查询自己想要看到的新闻,那么这个存储新闻的地方需要有“存”和“取”这样的功能,这些功能我们一般都会用服务器端脚本语言开发,像是PHP,JAVA,来开发一个后台,然后可能用一个数据库,像是MySQL来存储内容。
而PHP是比较受欢迎的服务器端脚本语言,它本身是开源而且免费,使用广泛,比如我们常常用来搭建BLOG的WORDPRESS也是用PHP开发的,而且入门简单。
1.2、PHP都能够做什么(几乎兼容所有的web服务器,数据库):
PHP能够生成动态内容;
PHP能够创建、打开、读取、写入、删除以及关闭服务器上的文件;
PHP能够接收表单数据;
PHP能够发送并取回cookie;
PHP能够添加、删除、修改数据库中的数据;
PHP能够限制用户访问网站中的某些页面;
PHP能够对数据进行加密解密;
……
2、Ajax-服务器端实现
2.1、了解了PHP,那么我们怎么来运行PHP:
我们需要有一个Web服务器来运行和承载PHP程序,一般来说我们都会在本地部署一个Web服务器用来测试,通过本地的Web服务器我们可以及时查看我们编写的PHP代码的实际效果,对于初学者来说,建立一个PHP环境比较复杂,最简单的方式就是选择一个一体化的软件包,这里推荐XAMMP(下载地址:https://www.apachefriends.org/download.html),它是一个功能强大的集成软件包,包含了web服务器,apache,MySQL数据库,PHP语言支持。
等XAMMP安装完成之后,我们需要在Dreamweaver中配置Web服务器用于本地测试(具体配置方法可点开超链接看看),其实Dreamweaver本身就支持XAMMP的配置。
配置完之后,我们进入DW页面之后,新建一个站点和服务器:
1、点击站点,新建站点。
2、然后会弹出一个框,站点名字可以自己取,保存的目录,我们需要找到XAMMP文件(我的目录名是XAMMP-shuju)里面的htdocs,然后再在htdocs文件下新建一个文件夹,命名为Ajaxdemo。
3、然后点击左侧 选项框里的服务器,在一个超大框下面有一个小加号,点击一下。
4、网络选择本地/网络。
5、服务器文件夹选择刚刚第二步的文件夹,Web URL填写http://localhost:8080/Ajaxdemo
。
6、点击高级选项,里面的服务器模型选择PHP MySQL。
7、在保存之前,到基本选项框下,将远程的对号取消,勾上测试,再点击保存,这样一个站点就建好了。
下面我们可以在这个新建好的站点下新建一个文件:
1、可以将新文件命名为text.php,输入代码。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
</head>
<body>
<h1>这是一个测试页面
<?php
echo "hello world"
?>
</h1>
</body>
</html>
2、然后打开浏览器预览,这里就是PHP运行成功后的结果了。
这里浅略讲解一下刚刚的PHP代码:
PHP脚本以
<?php
开头,以?>
结尾;PHP文件的默认文件扩展名是
.php
;PHP语句以分号结尾(
;
)。
2.2、接着最开始我们说的例子的服务端代码
然后接着最开始我们说的例子,这是服务端代码我在这里给它命名为(service.php):
<?php
/*设置页面内容是html编码格式utf-8,
设置后可以防止页面放返回的值乱码,
header里面就是告诉客户端,我们服务端
响应的内容格式是什么?
*/
header("Content-Type:text/plain;charset=utf-8");//告诉服务器相应的文本格式指什么,这里的格式是纯文本
//header("Content-Type:application/json;charset=utf-8");//格式是json子符串
//header("Content-Type:text/xml;charset=utf-8");
//header("Content-Type:text/html;charset=utf-8");
//header("Content-Type:application/javascript;charset=utf-8");
//定义一个多维数组,包含员工的信息,每条员工信息为一个数组
$staff = array
(
array("name" => "洪七" , "number" => "101" , "sex" => "男" , "job" => "总经理"),
array("name" => "展昭" , "number" => "102" , "sex" => "男" , "job" => "工程师"),
array("name" => "龙女" , "number" => "103" , "sex" => "女" , "job" => "理财员"),
);
//判断如果是GET请求,则进行搜索;如果是POST请求,则进行新建;
//$_SERVER是一个超全局变量,在一个脚本的全部作用域中都可用,不用使用global关键字;
//$_SERVER["REQUEST_METHOD"]返回访问页面使用的请求方法;
if($_SERVER["REQUEST_METHOD"] == "GET")
{
search();
}elseif($_SERVER["REQUEST_METHOD"] == "POST")
{
create();
}
//通过员工编号搜索员工
function search()
{
//检查是否有员工编号的参数
//isset检测变量是否设置;empty判断值是否为空
//超全局变量$_GET和S_POST用于收集表单数据
if(!isset($_GET["number"]) || empty($_GET["number"]))
{
echo "参数错误";
return;
}
//函数之外声明的变量拥有Global作用域,只能在函数以外进行访问.
//global关键字用于访问函数内的全局变量
global $staff;
//获取number参数
$number = $_GET['number'];
$result = "没有找到员工";
//遍历$staff多维数组,查询key值为number的员工是否存在,如果存在,则修改返回结果
foreach ($staff as $value) {
if($value["number"] == $number)
{
$result = "找到员工:员工编号:".$value["number"].",员工姓名:".$value["name"].
",员工性别:".$value["sex"].",员工职位:".$value["job"];
break;
}
}
echo $result;
}
//创建员工
function create()
{
//判断信息是否填写完全
if(!isset($_POST["name"]) || empty($_POST["name"])
|| !isset($_POST["number"]) || empty($_POST["number"])
|| !isset($_POST["sex"]) || empty($_POST["sex"])
|| !isset($_POST["job"]) || empty($_POST["job"]))
{
echo "参数错误,员工信息填写不全";
return;
}
//TODO:获取POST表单数据并保存到数据库
//提示保存成功
echo "员工:".$_POST['name']."信息保存成功!";
}
?>
3、PHP服务器端代码测试
服务器端的代码我们已经写完了,但是这个代码写的对不对,能不能运行,我们需要进行一下测试,我们需要在没有客户端的情况下,就对服务端的一些请求进行一些测试。
这是怎么做到的呢?我们需要一个工具,叫做Fiddler(具体的Fiddler下载、安装、使用、教程,可点击超链接),它可以监听电脑上所有发出的http请求,监听它们传出的值和响应回来的值,当然在这里面它还可以去模拟。
怎么来使用这个工具呢
1、首先点开右上方的composer2、然后在我们之前建立的服务端的地址给填写里面,这里我们用GET请求,然后点击Execute;
3、然后做左边就会有一条记录,我们双击一下,因为没有参数,这里的运行结果达到了我们的预期;
4、接着我们在URL中加入一个参数?number=
,然后给number加一个值,我们可以试试1,有
因为我们刚刚约定了三个员工,对应仨个数,分别是101,102,103,而1不属于其中,所以“没有找到员工”,如果我们给1改成102,看看运行结果:
这也就是说,我们的GET请求服务端是没有问题的,接着我们换一个POST请求,这里要注意,我们在前面说过,post请求
需要加上Content-Type:application/x-www-form-urlencoded
(告诉服务器这是一个post请求,请求的内容是通过URL这种方式发送过来的),因为是POST请求,我们这里不需要参数,然后我们直接调用一下,发现返回错误。
为什么呢?因为我们压根就没有填写,这里我们要填写一下信息:name=欧阳锋&number=104&sex=男&job=测试经理,也就是我们的请求正文,
然后我们运行一下,可以看到服务器还是返回出了结果。
4、客户端实现
说完了服务端的实现,我们现在来讲讲客户端的实现。
客户端的实现,首先我们需要新建一个文件,我们在DW中新建一个HTML的静态页面,把它做一个保存。
我们要实现不仅仅是这一个静态页面,我们要创建的是要通过上面的按钮来使用Ajax异步的方式发送请求,调用后台的服务方法,然后把服务方法返回来的值显示在页面上,这个显示是局部刷新这样的结果内容。那么,这样需要怎么做呢?
其实我们前面已经提到了,核心就是创建XMLHttpRequest对象,并发送异步请求,接着监听服务器的响应结果,并把它呈现在页面上。
主要分为两个部分,一个是员工查询,一个是员工创建,具体代码如下:
<!dOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ajax的demo</title>
<style type="text/css">
body,input,button,select,h1{
font-size: 15px;
line-height: 1.2;
}
</style>
</head>
<body>
<h1>员工查询</h1>
<label>请输入员工编号:</label>
<input type="text" id="keyword">
<br />
<button id="search">查询</button>
<p id="searchResult"></p>
<h1>员工创建</h1>
<label>请输入员工姓名:</label>
<input type="text" id="staffName">
<br />
<label>请输入员工编号:</label>
<input type="text" id="staffNumber">
<br />
<label>请选中员工性别:</label>
<select id="staffSex">
<option>男</option>
<option>女</option>
</select>
<br />
<label>请输入员工职位:</label>
<input type="text" id="staffJob">
<br />
<button id="save">保存</button>
<p id="createResult"></p>
<script type="text/javascript">
//通过员工编号搜索员工
document.getElementById('search').onclick = function()
{
//发送Ajax查询请求并处理
var request = new XMLHttpRequest();
request.open("GET","service.php?number="+document.getElementById("keyword").value);//因为我将前面的服务端PHP代码和我这个客户端HTML代码放在了一个目录下,所以就直接写了,要注意这个请求还需要带一个地址,地址上还需要带一个参数,也就是员工编号参数number,那number又是从上面员工查询下面的keyword来取的,所以说number的参数取值是document.getElementById("keyword").value
request.send();//发出请求
//监听事件
request.onreadystatechange = function()
{
if(request.readyState === 4)
{
if(request.status === 200)
{
//都成功后更新页面信息,获取服务器响应结果然后赋值页面标签
document.getElementById("searchResult").innerHTML = request.responseText;
}
else
{
//抛异常,弹出错误码
alert("发生错误:" + request.status);
}
}
}
}
//创建员工
document.getElementById('save').onclick = function()
{
// alert(1);
//发送Ajax查询请求并处理
var request = new XMLHttpRequest();
request.open("POST","service.php");//open方法第三个参数不用传,默认异步
var data = "name=" + document.getElementById("staffName").value
+ "&number=" + document.getElementById("staffNumber").value
+ "&sex=" + document.getElementById("staffSex").value
+ "&job=" + document.getElementById("staffJob").value;
//设置http头信息,告诉web服务器我们发送的是一个表单,然后才能发送,必须位置open和send方法之间
request.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
request.send(data);//发出请求
//监听事件
request.onreadystatechange = function()
{
if(request.readyState === 4)
{
if(request.status === 200)
{
//都成功后更新页面信息,获取服务器响应结果然后赋值页面标签
document.getElementById("createResult").innerHTML = request.responseText;
}
else
{
//抛异常,弹出错误码
alert("发生错误:" + request.status);//服务器地址错误会返回错误码
}
}
}
}
</script>
</body>
</html>
运行一下可以得到:
三、JSON格式
1、JSON基本概念
JSON:JavaScript对象表示法(JavaScript Object Notation)。
JSON是存储和交换文本信息的语法,类似于XML。它采用键值对的方式来组织,易于人们阅读和编写,同事也易于及其解析和生成。
JSON是独立于语言的,也就是不管什么语言,都可以解析JSON,只需要按照JSON的规则来就行。
1.1、JSON与XML比较:
1、JSON的长度和XML格式比起来很短小,在网络传输的过程中,可以大大的减少带宽;
2、JSON读写的速度更快;
3、JSON可以使用JavaScript内建的方法直接进行解析,转换成JavaScript对象,十分方便。
1.2、JSON语法规则
JSON数据的书写格式是:名称/值对
。(数据要用英文逗号来分隔)
名称/值对
组合中的名称写在前面(在双引号中),值对写在后面(同样在双引号中),中间用冒号隔开:比如“name”:“郭靖”
,这里和JavaScript不一样,JavaScript不需要加引号。
JSON的值还可以是下面这些类型:
数字(整数或者浮点型),比如123,1.23;
字符串(在双引号中);
逻辑值(ture或false);
数组(在方括号中);
对象(在花括号中);
null(表示这个键值没有值)。
{
"staff":[
//staff是名称,这里的数组是值对,这个数组又是有三个小的阶层对象组成,每个对象里面又有两个属性
{"name":"洪七","age":70},
{"name":"郭靖","age":35},
{"name":"黄蓉","age":30},
]
}
2、JSON解析、格式化和校验工具
那么JSON的格式怎么在js中解析呢,一般来说js中解析JSON有两种方式,eval和JSON.parse,我们在浏览器的控制台中演示这两种方式。
2.1、JSON解析
2.1.1、eval的演示:
首先我们建立一个JSON字符串,注意放在一行里面,否则会报错,然后建立一个jsonobj,我们通过eval的方式解析这样的一个JSON字符串。
怎么样来解析呢?通过eval( '(' + jsondata + ')')
。解析之后呢?我们可以alert其中的一个属性,比如staff,因为staff是一个数组,所以我们可以取它的数组中的第一个值,name,然后会弹出来一个图片演示中的洪七,这就是解析成功了。
var jsondata = '{"staff":[{ "name":"洪七","age":70 },{ "name":"郭靖","age":35 },{ "name":"黄蓉","age":30 }]}';
var jsonobj = eval( '(' + jsondata + ')');
alert(jsonobj.staff[0].name);
2.1.2、JSON.parse的演示
JSON.parse的方式效果其实和eval差不多,只需要注意第二行的改变。
var jsondata = '{"staff":[{ "name":"洪七","age":70 },{ "name":"郭靖","age":35 },{ "name":"黄蓉","age":30 }]}';
var jsonobj = JSON.parse(jsondata);
alert(jsonobj.staff[0].name);
2.1.3、那么这两种方式我们选哪一个呢?
再给大家举个例子:
假如说我们把这个JSON字符串稍微做一下改动,把里面的里面洪七的age的70改成alert(123)
,这时候我们使用eval的方法来看一下:
var jsondata = '{"staff":[{ "name":"洪七","age":alert(123) },{ "name":"郭靖","age":35 },{ "name":"黄蓉","age":30 }]}';
var jsonobj = eval( '(' + jsondata + ')');
alert(jsonobj.staff[0].name);
运行之后会发现,先弹出123,点击确认,然后弹出洪七。这说明eval解析的方式,不光解析了JSON字符串,而且还执行了JSON字符串里面的一些方法。
但是用第二种方式呢?
var jsondata = '{"staff":[{ "name":"洪七","age":alert(123) },{ "name":"郭靖","age":35 },{ "name":"黄蓉","age":30 }]}';
var jsonobj = JSON.parse(jsondata);
alert(jsonobj.staff[0].name);
大家会发现什么都不弹出来了,在控制台还弹出了错误,告诉我们这样写不合法,语法错误。
也就是说eval解析中,不会去看我们JSON字符串是否合法,而且JSON字符串里的一些方法会直接执行,这是非常的危险,作为js程序员要牢记在代码中,无论何时我们使用eval方法时都是非常危险的,除非我们可以确保eval中的参数是可以控制的,安全的,尤其是我们用eval去解析第三方的JSON数据有可能会包含恶意代码,而且JSON.parse还可以给我们汇报一些关于JSON字符串里面的错误,既安全又方便,所以我们在实际应用中最好使用JSON.parse。
2.2、JSON的格式化,校验
虽然JSON的这种格式比较简短,语法也比较的简单,但是我们在写起来的时候有很多的符号,非常容易出错,所以把JSON字符串进行格式化,校验,就显得必不可少。
这里我推荐一款在线的JSON校验工具JSONLint(地址:jsonlint.com).
我们把刚才的JSON字符串{"staff":[{ "name":"洪七","age":alert(123) },{ "name":"郭靖","age":35 },{ "name":"黄蓉","age":30 }]}
拿过来,粘贴在里面,直接点击校验(validate JSON),它就能直接校验出我们JSON字符串里的语法错误,比如说alert(123)
,这肯定是不行的。
然后我们给alert(123)改成70,就通过了。
接着我们就把刚才的例子用JSON的方式去改写一下,在改写之前,我们做一个格式上的约定,我们约定所有从服务器上返回的JSON字符串应该长成:
{
"success": true,
"msg": "xxx"
}
它有两个属性,一个是success,它代表是否成功,这个成功不是我们刚刚指的请求是否出错,而是代表是否正确的去执行,比如说我们的参数错误,就代表不成功,说明我们的参数就没有给全,更别提执行了,当我们参数正确的情况下,能正确执行之后,我们这个返回的成功应该是true,也就是这是我们逻辑成功的一个标志。在我们使用AJAX来进行服务器请求和服务器响应的过程中,我们经常会做这样的一个标记的约定。一般我们把这个success作为请求是否成功,把msg作为请求的返回值,甚至我们还可以再加上一些属性,比如说data,作为请求返回的数据,而msg只作为success为false时的给出的一些错误信息,或者我们可以把msg改为errormsg等等。
这个约定是要前后都遵守,而且都按照这个约定来编程,这样就可以大大简化我们的一些错误的判断。
这里我们就简单的用success代表是否正确,而msg代表返回的信息,要做到这一点,我们需要对服务端进行一些小小的改造,如何改造呢?我们将之前所有的返回值都采用{"success":false/true,"msg":"返回的信息"}
:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>service</title>
</head>
<body>
<?php
/*设置页面内容是html编码格式utf-8,
设置后可以防止页面放返回的值乱码,
header里面就是告诉客户端,我们服务端
响应的内容格式是什么?
*/
//header("Content-Type:text/plain;charset=utf-8");//告诉服务器相应的文本格式指什么,这里的格式是纯文本
header("Content-Type:application/json;charset=utf-8");//格式是json子符串
//header("Content-Type:text/xml;charset=utf-8");
//header("Content-Type:text/html;charset=utf-8");
//header("Content-Type:application/javascript;charset=utf-8");
//定义一个多维数组,包含员工的信息,每条员工信息为一个数组
$staff = array
(
array("name" => "洪七" , "number" => "101" , "sex" => "男" , "job" => "总经理"),
array("name" => "展昭" , "number" => "102" , "sex" => "男" , "job" => "工程师"),
array("name" => "龙女" , "number" => "103" , "sex" => "女" , "job" => "理财员"),
);
//判断如果是GET请求,则进行搜索;如果是POST请求,则进行新建;
//$_SERVER是一个超全局变量,在一个脚本的全部作用域中都可用,不用使用global关键字;
//$_SERVER["REQUEST_METHOD"]返回访问页面使用的请求方法;
if($_SERVER["REQUEST_METHOD"] == "GET")
{
search();
}elseif($_SERVER["REQUEST_METHOD"] == "POST")
{
create();
}
//通过员工编号搜索员工
function search()
{
//检查是否有员工编号的参数
//isset检测变量是否设置;empty判断值是否为空
//超全局变量$_GET和S_POST用于收集表单数据
if(!isset($_GET["number"]) || empty($_GET["number"]))
{
echo '{"success":false,"msg":"参数错误"}';
return;
}
//函数之外声明的变量拥有Global作用域,只能在函数以外进行访问.
//global关键字用于访问函数内的全局变量
global $staff;
//获取number参数
$number = $_GET["number"];
$result = '{"success":false,"msg":"没有找到员工"}';
//遍历$staff多维数组,查询key值为number的员工是否存在,如果存在,则修改返回结果
foreach ($staff as $value) {
if($value["number"] == $number)
{
$result = '{"success":true,"msg":"找到员工:员工编号:'.$value["number"].',员工姓名:".$value["name"].
",员工性别:".$value["sex"].",员工职位:".$value["job"]}';
break;
}
}
echo $result;
}
//创建员工
function create()
{
//判断信息是否填写完全
if(!isset($_POST["name"]) || empty($_POST["name"])
|| !isset($_POST["number"]) || empty($_POST["number"])
|| !isset($_POST["sex"]) || empty($_POST["sex"])
|| !isset($_POST["job"]) || empty($_POST["job"]))
{
echo '{"success":true,"msg":"参数错误,员工信息填写不全"}';
return;
}
//TODO:获取POST表单数据并保存到数据库
//提示保存成功
echo '{"success":true,"msg":"员工:'.$_POST['name'].'信息保存成功!"}';
}
?>
</body>
</html>
下面改造我们的客户端:
怎么改造呢?我们客户端就不能直接输出服务器端的JSON文本,如果直接输出会出现下面图片中的情况:
我们会直接把这个服务器端返回的JSON字符串直接显示出来,这样对于用户使用很不友好,我们需要判断是否成功,来显示对应的内容。怎么判断呢?要想判断我们需要声明一个变量,然后去parse服务器端传来的内容,parse之后,直接读取属性,JSON字符串成了JSON对象,我们就可以进行判断。
<!dOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ajax的demo</title>
<style type="text/css">
body,input,button,select,h1{
font-size: 15px;
line-height: 1.2;
}
</style>
</head>
<body>
<h1>员工查询</h1>
<label>请输入员工编号:</label>
<input type="text" id="keyword">
<br />
<button id="search">查询</button>
<p id="searchResult"></p>
<h1>员工创建</h1>
<label>请输入员工姓名:</label>
<input type="text" id="staffName">
<br />
<label>请输入员工编号:</label>
<input type="text" id="staffNumber">
<br />
<label>请选中员工性别:</label>
<select id="staffSex">
<option>男</option>
<option>女</option>
</select>
<br />
<label>请输入员工职位:</label>
<input type="text" id="staffJob">
<br />
<button id="save">保存</button>
<p id="createResult"></p>
<script type="text/javascript">
//通过员工编号搜索员工
document.getElementById('search').onclick = function()
{
//发送Ajax查询请求并处理
var request = new XMLHttpRequest();
request.open("GET","service.php?number=" + document.getElementById("keyword").value);//因为我将前面的服务端PHP代码和我这个客户端HTML代码放在了一个目录下,所以就直接写了,要注意这个请求还需要带一个地址,地址上还需要带一个参数,也就是员工编号参数number,那number又是从上面员工查询下面的keyword来取的,所以说number的参数取值是document.getElementById("keyword").value
request.send();//发出请求
//监听事件
request.onreadystatechange = function()
{
if(request.readyState === 4)
{
if(request.status === 200)
{
var data = JSON.parse(request.responseText);
if(data.success){
document.getElementById("searchResult").innerHTML = data.msg;
}else{
document.getElementById("searchResult").innerHTML = "出现错误:" + data.msg;
}
//都成功后更新页面信息,获取服务器响应结果然后赋值页面标签
}
else
{
//抛异常,弹出错误码
alert("发生错误:" + request.status);
}
}
}
}
//创建员工
document.getElementById('save').onclick = function()
{
// alert(1);
//发送Ajax查询请求并处理
var request = new XMLHttpRequest();
request.open("POST","service.php");//open方法第三个参数不用传,默认异步
var data = "name=" + document.getElementById("staffName").value
+ "&number=" + document.getElementById("staffNumber").value
+ "&sex=" + document.getElementById("staffSex").value
+ "&job=" + document.getElementById("staffJob").value;
//设置http头信息,告诉web服务器我们发送的是一个表单,然后才能发送,必须位置open和send方法之间
request.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
request.send(data);//发出请求
//监听事件
request.onreadystatechange = function()
{
if(request.readyState === 4)
{
if(request.status === 200)
{
var data = JSON.parse(request.responseText);
if(data.success){
document.getElementById("createResult").innerHTML = data.msg;
}else{
document.getElementById("createResult").innerHTML = "出现错误:" + data.msg;
}
//都成功后更新页面信息,获取服务器响应结果然后赋值页面标签
}
else
{
//抛异常,弹出错误码
alert("发生错误:" + request.status);//服务器地址错误会返回错误码
}
}
}
}
</script>
</body>
</html>
四、jQuery中的AJAX
了解了Ajax本身的原理,也了解了JSON字符串来进行信息的传递,通常来说呢,我们不会直接的原生的去实现Ajax请求,我们常常会在页面中用第三方的Ajax库,比如jQuery之类的,这些Ajax库已经封装了类似于Ajax请求的方法,这样我们在实际请求中可以不用再去关注浏览器的兼容性和实现,也可以很方便的调用这些第三方库里面的这一些方法,可以大大的简化我们的操作,这里我们以jQuery为例介绍一下怎么实现Ajax。
jQuery本身提供了一个Ajax方法,用这方法就可以实现Ajax请求,如何来实现呢?其实jQuery的Ajax给出了很多设定值。我们可以通过一个常用的设定值,就可以完成一个简单的请求,并且来得知它是不是成功,还是失败。
下面列出了Ajax方法非常常用的一些设置:
type:类型,“POST”或“GET”,默认为“GET”
url:发送请求的地址
data:是一个对象,连同请求发送到服务器的数据
dataType:预期服务器返回的数据类型。如果不指定,jQuery将自动根据HTTP包MIME信息来智能判断,一般我们采用JSON格式,可以设置为“JSON”
success:是一个方法,请求成功后的回调函数,传入返回后的数据,以及包含成功代码的字符串
error:是个方法,请求失败时调用此函数。传入XMLHttpRequest对象
那么,我们用jQuery来改写一下刚才的例子(这里我就不下载jQuery的库到本地了,我们直接引用一个在线的地址,这个在线的地址在BootCDN的静态资源库,它包含了我们常用的一些库,比如我们的jQuery),引用了之后呢,我们需要对jQuery进行初始化,我们采用这个方法$(document).ready(function(){ });
,也就是页面载入完毕之后,我们执行内部的一些事情。
<!dOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ajax的demo</title>
<style type="text/css">
body,input,button,select,h1{
font-size: 15px;
line-height: 1.2;
}
</style>
</head>
<body>
<h1>员工查询</h1>
<label>请输入员工编号:</label>
<input type="text" id="keyword">
<br />
<button id="search">查询</button>
<p id="searchResult"></p>
<h1>员工创建</h1>
<label>请输入员工姓名:</label>
<input type="text" id="staffName">
<br />
<label>请输入员工编号:</label>
<input type="text" id="staffNumber">
<br />
<label>请选中员工性别:</label>
<select id="staffSex">
<option>男</option>
<option>女</option>
</select>
<br />
<label>请输入员工职位:</label>
<input type="text" id="staffJob">
<br />
<button id="save">保存</button>
<p id="createResult"></p>
<script src="http://apps.bdimg.com/libs/jquery/1.11./jquery.js"></script>
<script>
$(document).ready(function(){
$("#search").click(function(){
$.ajax({
type:"GET",
url:"service.php?number=" + $("keyword").val(),
dataType:"json",
success:function(data){
if(data.success){
$("#searchResult").html(data.msg);
}else{
$("#searchResult").html("出现错误" + data.msg);
}
},
error:function(jqXHR){
alert("发生错误:" + jqXHR.status);
}
});
});
$("#save").click(function(){
$.ajax({
type:"POST",
url:"service.php",
dataType:"json",
data:{
name:$("#staffName").val(),
number:$("#staffNumber").val(),
sex:$("#staffSex").val(),
job:$("#staffJob").val(),
},
success:function(data){
if(data.success){
$("#createResult").html(data.msg);
}else{
$("#createResult").html("出现错误" + data.msg);
}
},
error:function(jqXHR){
alert("发生错误:" + jqXHR.status);
});
</script>
</body>
</html>
五、跨域
一个域名地址的组成:
http:// www . abc,com : 8080 / scripts/jquery.js
协议 子域名 主域名 端口号 请求资源地址
1、处理跨域方式–代理
当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。
不同域直接相互请求资源,就算做“跨域”,比如:http://www.abc.com/index.html
请求http://www.efg.com/service.php
JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象。什么是跨域呢?简单的理解就是因为JavaScript同源策略的限制,a.com域名下的js无法操作b.com或者是c.a.com域名下的对象。
www.abc.com/index.html 调用 www.abc.com/service.php (非跨域)
www.abc.com/index.html调用 www.efg.com/service.php (跨域)
www.abc.com/index.html调用 bbs.abc.com/service.php (跨域)
www.abc.com/index.html调用www.abc.com:81/service.php(跨域)
www.abc.com/index.html调用 https://www.abc.com/service.php(跨域)
再补充说明一下子域名这个概念。
比如我们有一个主域名abc.com
,那么它的子域名有多种,也可以是很多级,比如二级,或者比如三级。这些都统称为它的子域名。那么它的子域名只要不相同,都会被认作为跨域。
那我们处理跨域都有哪些方法呢?因为这是一个非常常见的问题。我们总是需要跨域来访问,当我们网站比较大的时候,可能要全国都要去部署。可能我们一个服务器在上海,一个服务器在北京,一个在广州,一个在深圳,甚至于一个在国外,那么处理跨域第一个最常见的方法,就是在同域名的Web服务器上,创建一个代理。比如说我们北京的Web服务器,往北京要想调用上海的服务,我们不从前端直接调用上海服务,我们从前端直接调用北京的同名服务。举个例子来说,在上海服务器上,有一个服务,那我们在北京服务器上也建一个这个服务。北京这个服务干什么呢?其实是从后端访问上海的这个服务,然后把服务的响应值获取过来,返回给前端,也就是北京的这个服务是在后端做了一个代理,这样前端只需要访问北京的这样一个代理的服务,也就相当于访问了上海这样一个服务。当然这种代理已经属于后台的技术。
2、处理跨域方式–JSONP
处理跨域呢,还有第二个方法,就是处理JSONP。JSONP呢?可以去解决主流浏览器他们的get请求,跨越数据访问的问题。
它的原理是什么呢?它的原理是这样的。
在www.aaa.com页面中:
<script>
function jsonp(json){
alert(json["name"]);
}
</script>
<script src="http://www.bbb.com/jsonp.js"></script>
在www.bbb.com页面中;
jsonp({'name':'洪七','age':24});
在某个域名的页面中,我们可以这样声明一段js代码。也就是我们定义这样一个方法。然后在下面呢我们可以去载入另外一个域名上面的js,也就是说就是说我们scrip这样一个标签,它是可以向不同的那个命名去提交HTTP请求的。然后载入了另外一个域名,这个js方法呢它可能是直接去调用第一个域名上面声明的这样一个方法,也就是说对域名去声明,避免去调用。
其实这种处理方式和我们的XMLHttpRequest,这样一个Ajax方式就没有太大关系。它只是借用了这个scrip这样一个标签节点,它可以跨域去访问,去获取的一个特性。
我们我们来看一看怎么样来使用。使用的方法非常简单,在get请求这一段代码中,我们需要修改一下dataType,把它从json改为jsonp,接着我们再增加一个属性,这个属性名字就叫jsonp。而它的值我们可以任意写,比如在这里我们写上callback。
<!dOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ajax的demo</title>
<style type="text/css">
body,input,button,select,h1{
font-size: 15px;
line-height: 1.2;
}
</style>
</head>
<body>
<h1>员工查询</h1>
<label>请输入员工编号:</label>
<input type="text" id="keyword">
<br />
<button id="search">查询</button>
<p id="searchResult"></p>
<h1>员工创建</h1>
<label>请输入员工姓名:</label>
<input type="text" id="staffName">
<br />
<label>请输入员工编号:</label>
<input type="text" id="staffNumber">
<br />
<label>请选中员工性别:</label>
<select id="staffSex">
<option>男</option>
<option>女</option>
</select>
<br />
<label>请输入员工职位:</label>
<input type="text" id="staffJob">
<br />
<button id="save">保存</button>
<p id="createResult"></p>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script>
$(document).ready(function(){
$("#search").click(function(){
$.ajax({
type:"GET",
url:"http://http://127.0.0.1:8080/Ajaxdemo/service.php?number=" + $("#keyword").val(),
dataType:"jsonp",
jsonp:"callback",
success:function(data){
if(data.success){
$("#searchResult").html(data.msg);
}else{
$("#searchResult").html("出现错误" + data.msg);
}
},
error:function(jqXHR){
alert("发生错误:" + jqXHR.status);
}
});
});
$("#save").click(function(){
$.ajax({
type:"POST",
url:"http://http://127.0.0.1:8080/Ajaxdemo/service.php",
dataType:"json",
data:{
name:$("#staffName").val(),
number:$("#staffNumber").val(),
sex:$("#staffSex").val(),
job:$("#staffJob").val(),
},
success:function(data){
if(data.success){
$("#createResult").html(data.msg);
}else{
$("#createResult").html("出现错误" + data.msg);
}
},
error:function(jqXHR){
alert("发生错误:" + jqXHR.status);
}
});
});
});
</script>
</body>
</html>
也就是说我们对代码做了两处改动,第一处改动把dataType从json改成了jsonp,第二处改动是增加了一个jsonp的属性,把它起了一个值,叫callback,当然我们也可以起任意值callback123等等。
这是对前端的改造。
我们同样在这个get请求的处理中,获取到callback。为什么这里是back呢?注意我们在前端把这个参数取的名字是callback,所以我们后端需要获取到它,如果我们在前端把这个参数取的名字是callback123,那么我们后端就需要获取callback123。也就是说这个值是我们参数的名称。
那么我们要对返回值做一个改造。刚才我们也介绍了jsonp这样一种方式,我们的返回值需要用括号把我们要返回的json对象的值用括号括起来,前面加上我们获取到的这个参数的值。同样的,上面也是这样操作。大家注意php代码中连接字符串使用点号,不像我们js代码中用的是加号,这一点需要大家去注意。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>service</title>
</head>
<body>
<?php
/*设置页面内容是html编码格式utf-8,
设置后可以防止页面放返回的值乱码,
header里面就是告诉客户端,我们服务端
响应的内容格式是什么?
*/
//header("Content-Type:text/plain;charset=utf-8");//告诉服务器相应的文本格式指什么,这里的格式是纯文本
header("Content-Type:application/json;charset=utf-8");//格式是json子符串
//header("Content-Type:text/xml;charset=utf-8");
//header("Content-Type:text/html;charset=utf-8");
//header("Content-Type:application/javascript;charset=utf-8");
//定义一个多维数组,包含员工的信息,每条员工信息为一个数组
$staff = array
(
array("name" => "洪七" , "number" => "101" , "sex" => "男" , "job" => "总经理"),
array("name" => "展昭" , "number" => "102" , "sex" => "男" , "job" => "工程师"),
array("name" => "龙女" , "number" => "103" , "sex" => "女" , "job" => "理财员"),
);
//判断如果是GET请求,则进行搜索;如果是POST请求,则进行新建;
//$_SERVER是一个超全局变量,在一个脚本的全部作用域中都可用,不用使用global关键字;
//$_SERVER["REQUEST_METHOD"]返回访问页面使用的请求方法;
if($_SERVER["REQUEST_METHOD"] == "GET")
{
search();
}elseif($_SERVER["REQUEST_METHOD"] == "POST")
{
create();
}
//通过员工编号搜索员工
function search()
{
$jsonp = $_GET["callback"];
//检查是否有员工编号的参数
//isset检测变量是否设置;empty判断值是否为空
//超全局变量$_GET和S_POST用于收集表单数据
if(!isset($_GET["number"]) || empty($_GET["number"]))
{
echo '{"success":false,"msg":"参数错误"}';
return;
}
//函数之外声明的变量拥有Global作用域,只能在函数以外进行访问.
//global关键字用于访问函数内的全局变量
global $staff;
//获取number参数
$number = $_GET["number"];
$result = $jsonp.'({"success":false,"msg":"没有找到员工"})';
//遍历$staff多维数组,查询key值为number的员工是否存在,如果存在,则修改返回结果
foreach ($staff as $value) {
if($value["number"] == $number)
{
$result = $jsonp.'({"success":true,"msg":"找到员工:员工编号:'.$value["number"].',员工姓名:'.$value["name"].',员工性别:'.$value["sex"].',员工职位:'.$value["job"].'"})';
break;
}
}
echo $result;
}
//创建员工
function create()
{
//判断信息是否填写完全
if(!isset($_POST["name"]) || empty($_POST["name"])
|| !isset($_POST["number"]) || empty($_POST["number"])
|| !isset($_POST["sex"]) || empty($_POST["sex"])
|| !isset($_POST["job"]) || empty($_POST["job"]))
{
echo '{"success":false,"msg":"参数错误,员工信息填写不全"}';
return;
}
//TODO:获取POST表单数据并保存到数据库
//提示保存成功
echo '{"success":true,"msg":"员工:'.$_POST['name'].'信息保存成功!"}';
}
?>
</body>
</html>
后台代码就改造完了,我们刷新页面试一下吧。
大家会发现我们在这里实现跨域只是对get的请求进行了改造。并没有去改造post请求,这是什么原因呢?其实,就是这种原理大家也已经发现了,它只能对get的请求起到效果。
3、处理跨域方式–XHR2
HTML5为我们提供的XMLHttpRequest Level2已经实现了跨域访问已经其他的一些新功能,但是十分可惜,IE10以下版本还没有提供这样一个XMLHttpRequest的支持,并不是说IE10以下不支持,而是不支持XMLHttpRequest Level2的这样一个新版本的支持,如果你忽略IE,当然就可以采用这样一个方法。
这个这个方法非常简单。我们在服务器端把刚才的改动给撤销,然后回到服务端,做一些小小的改动即可。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>service</title>
</head>
<body>
<?php
/*设置页面内容是html编码格式utf-8,
设置后可以防止页面放返回的值乱码,
header里面就是告诉客户端,我们服务端
响应的内容格式是什么?
*/
//header("Content-Type:text/plain;charset=utf-8");//告诉服务器相应的文本格式指什么,这里的格式是纯文本
header("Content-Type:application/json;charset=utf-8");//格式是json子符串
header("Access-Control-Allow-Origin:*");
header("Access-Control-Allow-Methods:POST,GET");
//header("Content-Type:text/xml;charset=utf-8");
//header("Content-Type:text/html;charset=utf-8");
//header("Content-Type:application/javascript;charset=utf-8");
//定义一个多维数组,包含员工的信息,每条员工信息为一个数组
$staff = array
(
array("name" => "洪七" , "number" => "101" , "sex" => "男" , "job" => "总经理"),
array("name" => "展昭" , "number" => "102" , "sex" => "男" , "job" => "工程师"),
array("name" => "龙女" , "number" => "103" , "sex" => "女" , "job" => "理财员"),
);
//判断如果是GET请求,则进行搜索;如果是POST请求,则进行新建;
//$_SERVER是一个超全局变量,在一个脚本的全部作用域中都可用,不用使用global关键字;
//$_SERVER["REQUEST_METHOD"]返回访问页面使用的请求方法;
if($_SERVER["REQUEST_METHOD"] == "GET")
{
search();
}elseif($_SERVER["REQUEST_METHOD"] == "POST")
{
create();
}
//通过员工编号搜索员工
function search()
{
//检查是否有员工编号的参数
//isset检测变量是否设置;empty判断值是否为空
//超全局变量$_GET和S_POST用于收集表单数据
if(!isset($_GET["number"]) || empty($_GET["number"]))
{
echo '{"success":false,"msg":"参数错误"}';
return;
}
//函数之外声明的变量拥有Global作用域,只能在函数以外进行访问.
//global关键字用于访问函数内的全局变量
global $staff;
//获取number参数
$number = $_GET["number"];
$result = '{"success":false,"msg":"没有找到员工"}';
//遍历$staff多维数组,查询key值为number的员工是否存在,如果存在,则修改返回结果
foreach ($staff as $value) {
if($value["number"] == $number)
{
$result = '{"success":true,"msg":"找到员工:员工编号:'.$value["number"].',员工姓名:'.$value["name"].',员工性别:'.$value["sex"].',员工职位:'.$value["job"].'"}';
break;
}
}
echo $result;
}
//创建员工
function create()
{
//判断信息是否填写完全
if(!isset($_POST["name"]) || empty($_POST["name"])
|| !isset($_POST["number"]) || empty($_POST["number"])
|| !isset($_POST["sex"]) || empty($_POST["sex"])
|| !isset($_POST["job"]) || empty($_POST["job"]))
{
echo '{"success":false,"msg":"参数错误,员工信息填写不全"}';
return;
}
//TODO:获取POST表单数据并保存到数据库
//提示保存成功
echo '{"success":true,"msg":"员工:'.$_POST['name'].'信息保存成功!"}';
}
?>
</body>
</html>
总结
这里就是AJAX的全部介绍,下面前端继续扬帆起航!