10 分钟全面解析 Ajax 原理

212 阅读7分钟

这是我参与更文挑战的第 18 天,活动详情查看: 更文挑战

本文已收录至Github,欢迎 Star:github.com/Jackson0714…
个人网站:www.passjava.cn

阅读目录

一、什么是 AJAX 

二、提交 Form 表单的原理

三、提交请求和服务响应的原理

四、XMLHttpRequest 对象的知识

五、JQuery 实现 AJAX

六、优势

七、缺点

八、应用场景

九、不适用场景

阅读本文需要 30 分钟,请先收藏转发后再看。

先上原理图

0619ajax.jpg

(另外这张图是我在博客园画的图,所以水印是博客园的,也欢迎大家关注我的博客园。)

背景

  1. 传统的 Web 网站,提交表单,需要重新加载整个页面。

  2. 如果服务器长时间未能返回 Response,则客户端将会无响应,用户体验很差。

  3. 服务端返回 Response 后,浏览器需要加载整个页面,对浏览器的负担也是很大的。

  4. 浏览器提交表单后,发送的数据量大,造成网络的性能问题。

问题

  1. 如何改进?

  2. AJAX 是什么?

  3. 有什么优势?

  4. 有什么缺点?

一、什么是 AJAX 

1.1 为什么需要 AJAX

当需要从服务器获取数据,并刷新页面的操作,如果不采用 AJAX,则需要用提交整个表单的方式,当提交表单时,发送请求给服务器,页面需要等待服务器发送完 response 后,页面才能恢复操作。

1.2 AJAX 的概念

  1. AJAX = 异步 JavaScript 和 XML。

  2. AJAX 是一种用于创建快速动态网页的技术。

  3. 通过在后台与服务器进行少量数据交换,可以使网页实现异步更新。

  4. 可以在不重新加载整个网页的情况下,对网页的某部分进行更新。

1.3 什么叫异步

当前页面发送一个请求给服务器,当前页面不需要等待服务器响应才能操作网页。发送完请求之后,当前页面可以继续浏览,操作。

1.4 什么叫局部刷新

我们可以用两种方式来实现部分刷新。

(1) iframe 页面重载的方式。

这种方式虽然实现了部分刷新,但是是页面的重载,所以也会带来性能上的问题。

  • Step1. 在页面中定义一个 Iframe
<iframe id="indexFrame" name="index" width="1000" height="800"
   frameborder="0" marginwidth="0" marginheight="0" scrolling="yes" style="margin-top:100px;"></iframe>
  • Step2. 设置 iframe 的 src
var indexFrame = document.getElementById("indexFrame");
indexFrame.src = "introduction.php";
  • Step3. 添加一个 button 的点击事件,当点击这个 button 时,重新设置 Iframe 的 src,实现 iframe 里面的页面刷新。iframe 外面的内容不刷新。
<button id="room" onclick='IndexClick("room")'>Click Me!</button>
function IndexClick(moduleKey) {
    var indexFrame = document.getElementById("indexFrame");
    if(indexFrame == null)
    {
            indexFrame = parent.document.getElementById("indexFrame");
    }
    var url = "introduction.php";
    switch (moduleKey) {
        case "introduction":
            url = "introduction.php";
            break;
        case "room":
            url = "room.php";
            break;
        default:
            {
            }
    }
    indexFrame.src = url;
}

通过这种方式我们可以实现一个导航栏的功能:

(2)AJAX 方式

Step1.JavaScrpit 发送异步请求

Step2. 服务端查询数据库,返回数据

Step3. 服务端返回 Response

Step4. 客户端根据返回的 Response,来用 JavaScript 操作 DOM。

看下面的例子:

当我们切换 DropDownList 中的 Item 时,JavaScript 发送异步请求给 Server 端,Server 端返回数据,然后 JavaScript 将数据解析出来,拼接了一个 Table,将 Table 呈现在页面上。

二、提交 Form 表单的原理

2.1 代码

客户端代码:

<form id="form1" action="Test.ashx" method="get">
            您的姓名 1:<input type="text" name="fname" size="20" />
            <input type="submit" name="submit" value="Sumbit">
 </form>

服务端代码:

public void ProcessRequest (HttpContext context)
{
        //Delay
        for (int i = 0; i < 2; i++)
        {
            System.Threading.Thread.Sleep(1000);
        }
  
         //从 Requset.Form 中获取 fname 的值。使用 Form 获取请求的键值对的值的前提条件是 HTTP request Content-Type 值必须是"application/x-www-form-urlencoded" 或 "multipart/form-data".
        string fname = context.Request["fname"];
 
        context.Response.ContentType = "text/plain";
    //将字符串写入 HTTP 响应输出流。
        context.Response.Write("Hello World " + fname);
 }

2.2 将代码部署到 IIS

2.3 打开站点:

http://localhost:8003/Test.html

2.4 输入“Jackson0714”然后点击 Sumbit 按钮

页面会重新刷新,显示"Hello World Jackson0714"

2.5 提交 Form 表单后,页面发送请求和服务端返回响应的流程

 

2.6 通过抓包,我们可以得到 HTTP Headers

浏览器发送 HTTP 给服务端,采取的协议是 HTTP 协议。

在传输过程中,我们可以看下 HTTP Headers。

三、AJAX 提交请求和服务响应的原理

3.1 代码

客户端 HTML 代码:

<!DOCTYPE html>
 
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>
    <script type="text/javascript" src="Ajax.js"></script>
 
</head>
<body>
    <div id="Test" style="background-color:#40eeee">
        您的姓名 2:<input type="text" id="testGetName" size="20" />
        <button type="button" onclick="testGet();">Ajax Get 请求</button>
    </div>
         
    <div id="Test" style="background-color:#ff6a00">
        您的姓名 3:<input type="text" id="testPostName" size="20" />
        <button type="button" onclick="testPost();">Ajax Post 请求</button>
    </div>
  
    <div id="myDiv" />
 
</body>
</html>

客户端 JS 代码:

var xmlhttp = createRequest();
 
function testGet() {
    var fname = document.getElementById("testGetName").value;
    xmlhttp.open("GET", "Test.ashx?fname=" + fname + "&random=" + Math.random() , true);
    xmlhttp.onreadystatechange = callback;
    xmlhttp.send(null);
}
 
function testPost() {
    var fname = document.getElementById("testPostName").value;
    xmlhttp.open("POST", "Test.ashx?"  + "&random=" + Math.random() , true);
    xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
    xmlhttp.onreadystatechange = callback;
    xmlhttp.send("fname="+fname);
    
}
 
function createRequest() {
    var xmlhttp;
    if (window.XMLHttpRequest) {
        // code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp = new XMLHttpRequest();
    }
    else {
        // code for IE6, IE5
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    return xmlhttp
}
 
function callback() {
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
        document.getElementById("myDiv").innerHTML = xmlhttp.responseText;
    }
}

这里有一点需要注意

var xmlhttp = createRequest(); 。

  1. 让服务端能够操作这个变量 xmlhttp ,如果定义成局部变量,则服务端返回 response 时,不能对 xmlhttp 的属性赋值。回调函数要求 request 是全局的,才能访问这个变量和它的属性值。

  2. 定义成全局变量后,可能出现两个请求或多个请求共享同一个请求对象。而这个请求对象只能存放一个回调函数来处理服务器响应。当服务器返回两个请求的 Response 后,可能会调用后指定的回调函数。所以可能有两个完全不同的服务器响应由同一个回调函数处理,而这可能并不是正确的处理。解决办法是创建两个不同的请求对象。

服务端代码不变。

3.2 输入“Jackson0714”然后点击 Sumbit 按钮

页面不会刷新,在最下面显示"Hello World Jackson0714"

3.3 AJAX 发送请求和服务端返回响应的流程

 

3.4 通过抓包,我们可以得到 HTTP Headers

浏览器发送 HTTP 给服务端,采取的协议是 HTTP 协议。

在传输过程中,我们可以看下 HTTP Headers:

 

3.5 AJAX  GET 和 POST 方式区别

AJAX 发送请求和 POST 发送请求的代码如下:

//GET 方式
function testGet() {
    var fname = document.getElementById("testGetName").value;
    xmlhttp.open("GET", "Test.ashx?fname=" + fname + "&random=" + Math.random() , true);
xmlhttp.onreadystatechange = callback;
    xmlhttp.send(null);
}
  
//POST 方式
function testPost() {
    var fname = document.getElementById("testPostName").value;
    xmlhttp.open("POST", "Test.ashx?"  + "&random=" + Math.random() , true);
    xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
   xmlhttp.onreadystatechange = callback;
    xmlhttp.send("fname="+fname);
    
}
  1. 请求的 URL 中,POST 方式可以添加键值对,也可以不添加

2.GET 方式中,send 方法传递值无效。对于 IE 浏览器可以忽略 send() 方法的参数。但是对于 FireFox,必须提供一个 null 引用,否则回调行为将不规律。这是在编写客户端脚本时你会发现的一个跨浏览器兼容的问题。

3.POST 可以用 send 方法发送额外信息。发送的信息存放在 content 中

4.Post 方式需要指定 Request Header 的类型。Get 方式不需要指定。

5.GET 方式将参数暴露在 URL 中,POST 不暴露。

四、XMLHttpRequest 对象的知识

4.1 XMLHttpRequest 对象的方法

4.2 XMLHttpRequest 对象的属性

五、JQuery 实现 AJAX

下面的代码实现了当切换 DropDownList 的 item 时,触发 getWeeklyCalendar 方法,用 JQuery 的类库方法$.ajax 来发送 AJAX 请求。

客户端 JQuery 代码

function getWeeklyCalendar(name,currentDate,mode){
   $.ajax({
        type:'POST',
        url:'weekProcess.php',data:'func=getWeeklyCalender&name='+name+'&currentDate='+currentDate+'&   mode='+mode,
        success:function(data){
        paintWeeklyCandler(data);
      }
  });
}

后台成功返回 Response 后,执行 paintWeeklyCandler(data) 方法

后台 PHP 代码

<?php  //定义返回的 Response 的格式为 JSON 格式
    header('Content-type: text/json');<br>    //引入自定义的数据库连接文件
    include 'dbConfig.php';<br>   //引入自定义的设置 session 的文件
   include_once 'session.php';
   /*
   * Function requested by Ajax
   */
   if(isset($_POST['func']) && !empty($_POST['func']))
   {
        switch($_POST['func']){
          case 'getWeeklyCalender':
             getWeeklyCalender($_POST['name'],$_POST['currentDate'],$_POST['mode']);
            break;
        case 'getWeeklyStatus':
            getWeeklyStatus($_POST['name'],$_POST['currentDate'],$_POST['mode']);
            break;
       case 'getEvents':
            getEvents($_POST['date'],$_POST['name']);
            break;
       default:
            break;
   }
}
 
function getWeeklyCalender($name = '',$currentDate = '',$mode = '')
{
    //逻辑代码<br>    <br>      <br>    //返回 JSON 格式的 Response
    echo json_encode(array('result'=>$DaysOfWeekResultsArray));
}

六、优势

  1. 使用异步方式与服务器通信,页面不需要重新加载,页面无刷新

  2. 按需取数据,减少服务器的负担

  3. 使得 Web 应用程序更为迅捷地响应用户交互

4.AJAX 基于标准化的并被广泛支持的技术,不需要下载浏览器插件或者小程序,但需要客户允许 JavaScript 在浏览器上执行

  1. 浏览器的内容和服务端代码进行分离。页面的内容全部由 JAVAScript 来控制,服务端负责逻辑的校验和从数据库中拿数据。

七、缺点

  1. 安全问题:将服务端的方法暴露出来,黑客可利用这一点进行攻击

  2. 大量 JS 代码,容易出错

3.Ajax 的无刷新重载,由于页面的变化没有刷新重载那么明显,所以容易给用户带来困扰——用户不太清楚现在的数据是新的还是已经更新过的;现有的解决有:在相关位置提示、数据更新的区域设计得比较明显、数据更新后给用户提示等

  1. 可能破坏浏览器后退按钮的正常行为;

  2. 一些手持设备(如手机、PAD 等)自带的浏览器现在还不能很好的支持 Ajax

八、应用场景

  1. 对数据进行过滤和操纵相关数据的场景

  2. 添加/删除树节点

  3. 添加/删除列表中的某一行记录

  4. 切换下拉列表 item

  5. 注册用户名重名的校验

九、不适用场景

  1. 整个页面内容的保存

  2. 导航

参考资料:

《ASP.NET 4 高级程序设计》

《Head First AJAX》

AJAX 工作原理及其优缺点

msdn.microsoft.com/zh-cn/libra…

msdn.microsoft.com/en-us/libra…

msdn.microsoft.com/zh-cn/libra…

msdn.microsoft.com/zh-cn/libra…

欢迎关注我的公众号:「悟空聊架构

作者简介:8 年互联网职场老兵|全栈工程师|90 后超级奶爸|开源践行者|公众号万粉原创号主。 蓝桥签约作者,著有《JVM 性能调优实战》专栏,手写了一套 7 万字 SpringCloud 实战总结和 3 万字分布式算法总结。 欢迎关注我的公众号「悟空聊架构」,免费获取资料学习。

我是悟空,努力变强,变身超级赛亚人!