阅读 318

AJAX

同步交互和异步交互

所谓同步交互就是指当客户端向服务端和数据库发送数据之后,若要发送下一个请求需要等待服务端和数据库的响应结果。这就好比数据结构中的队列,一个执行完毕在执行下一个。也类似一些面向过程语言的代码执行顺序。

而异步交互就是指客户端向服务端发送数据之后,无需等待服务端和数据库的响应结果,就可以发送下一个请求。

如下图说明了同步交互和异步交互的区别:

image.png 异步交互与同步交互的劣势:

  • 破坏了浏览器的前进和后退机制
  • 后面逻辑依靠前面逻辑时,可能会出现问题
  • Ajax 对搜索引擎支持较弱
  • 容易引起 web 安全问题

Ajax 是什么

Ajax 全称 “Asynchronous JavaScript and XML” 被译为:异步 JavaScript 和 XML。

虽然 Ajax 中的 x 代表 XML,但是现在 JSON 的诸多优势 JSON 的使用比 XML 更加普遍。

JSON 和 XML 都用于在 Ajax 模型中封装数据

Ajax 涉及的技术

Ajax 并不是一个新技术,而是多个技术的整合:

  • HTML
  • CSS
  • JavaScript
  • DOM
  • XML
  • XMLHttpRequest 对象

XMLHttpRequest 是 Ajax 的核心。

XMLHttpRequest 对象提供了在客户端和服务端传输数据的功能,XMLHttpRequest 对象提供了通过 URL 方式来获取数据,只更新网页的一部分数据。

实现 Ajax 的步骤

  • 创建 Ajax 核心对象(XMLHttpRequest)
  • 通过 Ajax 核心对象的 open() 方法建立与服务端的链接
  • 构建请求的数据内容,通过核心对象的 send() 方法发送给服务端
  • 通过核心对象提供的 onreadystatechange 事件,监听服务端的通信状态
  • 接受处理服务端响应的结果
  • 将结果更新到页面

创建 XMLHttpRequest 对象

由于创建 Ajax 对象的方式在浏览器之间存在不同的情况所以需要编写一个自定义 js 文件来实现浏览器兼容。 主要兼容的是 IE 浏览器。

在其他非 IE 的主流浏览器中创建 Ajax 对象的方法为:new XMLHttpRequest(), 而在 IE 中又分为两种情况:

IE7 版本:new ActiveXObject("Msxml2.XMLHTTP") IE6 及以下版本:new ActiveXObject("Microsoft.XMLHTTP") Tools.js 文件如下:

Object.defineProperty(window, "createXMLHttpRequest", {
  value: function () {
    var httpRequest;
    // 如果是非IE浏览器
    if (window.XMLHttpRequest) {
      httpRequest = new XMLHttpRequest();
    }
    // 如果是 IE 浏览器
    else if (window.ActiveXObject) {
      try {
        // IE 7+
        httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
      } catch (e) {
        try {
          // IE 6-
          httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
        } catch (e) {}
      }
    }
    return httpRequest;
  },
});
复制代码

在 HTML 页面中引入之前创建的 Tools.js 文件,然后调用 createXMLHttpRequest 方法进行创建即可。

如下代码:

var ajax = createXMLHttpRequest();
console.log(ajax);
复制代码

返回的结果为一个 XMLHttpRequest 对象。

实现 Ajax 异步交互

接下来模拟发请求和获取响应数据的过程,还是依照上面的过程

以下 XHR 均代表 XMLHttpRequest

  • 创建 XHR 对象
  • 调用 XHR 对象的 open() 方法
  • 调用 XHR 对象的 send() 方法
  • 调用 onreadystatechange 监听服务端通信状态
  • 使用 readyState 属性判断服务端响应状态

open() 方法

open() 方法语法结构:

open(method, url[, async, user, password])

参数说明:

  • method:请求方法,get、post、put、delete 等
  • url:发送请求的 url
  • async:是否异步交互
  • user:用户名用于认证用途
  • password:用户密码

send() 方法

在调用 send() 方法时,用于发送数据,默认为异步发送,发送后立即返回; 若为同步发送等待响应后返回。send 方法不传入参数代表不发送数据,当请求方式为 gethead 时需要将主体设置为 null

readyState 属性

XHR 对象的 readyState 属性返回值:

  • 0:XHR 被初始化,未调用 open 方法
  • 1:XHR 调用 open
  • 2:XHR 调用 send
  • 3:下载中
  • 4:下载完成

readyState 属性放在 open() 之下和 send() 之下时,返回的结果都为 2,3,4;

当放在 open() 之上 createXMLHttpRequest 之下时,返回 1,2,3,4

responseText 属性

XHR 对象的 responseText 属性接受服务端对该请求的响应结果。

status 属性

XHRstatus 属性返回当前服务端状态响应码,常见的状态响应码如下:

  • 200:请求成功
  • 304:请求的资源伪未变化(没有改动)
  • 404:服务器端地址未找到

对于对于上面写法如果对 open() 方法写入的服务端地址不正确则返回一个 404 报错,如果请求正确则返回 200。

get 请求方式

通过表单提交的数据,如果是 get 方式提交的数据会在地址栏上进行显示。

在 Ajax 提交方式中如果使用 get 或者 head 方式提交数据时,send 方法中只能写入 null

若要提交数据需要在对服务器的请求网址中输入相应的参数。如下代码所示:

<body>
  <button id="btn">按钮</button>
  <script src="./myTools.js"></script>
  <script>
    var btn = document.getElementById("btn");
    btn.addEventListener("click", function () {
      var xhr = createXMLHttpRequest();
      xhr.open(
        "get",
        "http://localhost:63343/ricardo/Ajax/%E4%BB%A3%E7%A0%81/%E6%B5%8B%E8%AF%95xhr.html?_ijt=22k61vqrrkstdjmlf6eo3ug8iu?user=hello#"
      );
      xhr.send(null);
    });
  </script>
</body>
复制代码

get 请求方式会直接在地址栏中追加数据。

POST 请求方式

在使用 POST 发送请求时,可以写在 XHR 中的 send() 方法中。 如下代码所示:

<body>
  <button id="btn">按钮</button>
  <script src="./myTools.js"></script>
  <script>
    var btn = document.getElementById("btn");
    btn.addEventListener("click", function () {
      var xhr = createXMLHttpRequest();
      xhr.open(
        "post",
        "http://localhost:63343/ricardo/Ajax/%E4%BB%A3%E7%A0%81/%E6%B5%8B%E8%AF%95xhr.html?_ijt=3b3upkr00lb4gtto8n5tb2o21u"
      );
      xhr.send("user=zhang&pwd=1234");
    });
  </script>
</body>
复制代码

结果:

image.png

在使用 POST 方式发送请求之前需要先使用 XHR 对象的 setRequestHeader() 方法设置请求头部信息。 如下代码所示:

var btn = document.getElementById("btn");
btn.addEventListener("click", function () {
  var xhr = createXMLHttpRequest();
  xhr.open(
    "post",
    "http://localhost:63343/ricardo/Ajax/%E4%BB%A3%E7%A0%81/%E6%B5%8B%E8%AF%95xhr.html?_ijt=3b3upkr00lb4gtto8n5tb2o21u"
  );
  // 使用 POST 请求设置请求头部信息
  xhr.setRequestHeader("Content-Type", "application/x-www-for-urlencoded");
  xhr.send("user=zhang&pwd=1234");
});
复制代码

当设置了头部信息之后,在浏览器的抓包工具中发现格式为:

image.png

server.js-创建一个自己的服务

var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]

if(!port){
  console.log('请指定端口号好不啦?\nnode server.js 8888 这样不会吗?')
  process.exit(1)
}

var server = http.createServer(function(request, response){
  var parsedUrl = url.parse(request.url, true)
  var pathWithQuery = request.url 
  var queryString = ''
  if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
  var path = parsedUrl.pathname
  var query = parsedUrl.query
  var method = request.method

  /******** 从这里开始看,上面不要看 ************/

  console.log('有个傻子发请求过来啦!路径(带查询参数)为:' + pathWithQuery)

  if(path === '/'){
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    response.write(`二哈`)
    response.end()
  } else if(path === '/x'){
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/css;charset=utf-8')
    response.write(`body{color: red;}`)
    response.end()
  } else {
    response.statusCode = 404
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    response.write(`你输入的路径不存在对应的内容`)
    response.end()
  }

  /******** 代码结束,下面不要看 ************/
})

server.listen(port)
console.log('监听 ' + port + ' 成功\n请用在空中转体720度然后用电饭煲打开 http://localhost:' + port)
复制代码
  • 使用node.server.js 8888启动
  • 添加index.html和main.js两个路由

总结

  • const request = new XMLHttpRequest
  • request.open("","")
    • request.onload()
    • request.onerror()
  • request.onreadystatechange()
  • request.send()

参考资料

文章分类
前端
文章标签