阅读 88

JS:AJAX 原理

AJAX 全称 Asynchronous JavaScript and XML,翻译为中文就是 异步的 JavaScript 与 XML 技术,指的是一套综合了多项技术的浏览器端网页开发技术。

AJAX 的诞生

实际上在 1998 年前后,AJAX 就已经诞生。当时微软的 Outlook Web Access 小组写了第一个允许客户端脚本发送 HTTP 请求(XMLHTTP)的组件。该组件原属于微软 Exchange Server,并且迅速地成为了 Internet Explorer 4.0 的一部分。

但直到 2005 年初,Google 开始在它旗下一些著名服务中广泛使用了异步通讯,如 Google、Google 地图、Gmail 等,Ajax 才被大众所接受。一个典型应用是当您在 Google 的搜索框输入关键字时,JavaScript 会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表。

Ajax 这个词被正式提出是由 Jesse James Garrett 的 《Ajax: A New Approach to Web Applications》一文。

The name is shorthand for Asynchronous JavaScript + XML, and it represents a fundamental shift in what’s possible on the Web.

—— Jesse James Garrett

AJAX 的意义

在 AJAX 为诞生之前的网页如果需要更新内容,必需重载整个网页。

AJAX 的诞生可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。

AJAX 的原理

XMLHttpRequest 是 AJAX 的基础。用于和服务器交换数据。

  • 我们可以通过 new 操作符创建一个 XMLHttpRequest 实例。IE 7 以及以后的所有主流浏览器均支持 XMLHttpRequest 对象(IE5 和 IE6 使用 ActiveXObject)。

    let XHR = new XMLHttpRequest()
    复制代码
  • 向服务器发送请求,需要使用 XMLHttpRequest 对象的 open()send() 方法:

    XHR.open('GET', 'test.txt', true)
    XHR.send()
    复制代码

    其中 open() 方法有三个参数:

    参数名称说明参数示例
    method请求的类型GET 或 POST
    url文件在服务器上的位置test.txt
    async异步true(异步)或 false(同步)
  • 当请求被发送到服务器时,需要准备接收来自服务器的响应,readyStatestatus 属性存有 XMLHttpRequest 的状态信息,当 readyState 改变时,就会触发 onreadystatechange 事件:

    XHR.onreadystatechange = () => {
      if (XHR.readyState == 4 && XHR.status == 200) {
        // 当 readyState 等于 4 且状态为 200 时,表示响应已就绪
      }
    }
    复制代码

    其中 readyState 存有 XMLHttpRequest 的状态:

    状态值状态说明
    0请求未初始化
    1服务器连接已建立
    2请求已接收
    3请求处理中
    4请求已完成,且响应已就绪
  • 接收来自服务器的响应,需要使用 XMLHttpRequest 对象的 responseText 或 responseXML 属性:

    let res = XHR.responseText
    复制代码

此时,一个基础的 AJAX 请求就已完成。

补充:同源策略

同源表示两个 URL 的 protocol、host 和 port 都是相同的。

{
  origin: 'https://developer.mozilla.org'
  protocol: 'https:'
  host: 'developer.mozilla.org'
  port: ''
}
复制代码

假如运行在 domain-a.com 的 JavaScript 代码发起了一个到 domain-b.com/data.json 的 AJAX 请求,出于同源策略,浏览器会限制脚本内发起的跨域请求。除非响应报文包含了正确 CORS(跨域资源共享) 响应头。

同源策略是一个重要的安全策略,它用于限制一个源(origin)的文档或者它加载的脚本如何能与另一个源的资源进行交互。如果缺少了同源策略,浏览器很容易受到 XSS、CSFR 等攻击。

补充:跨域请求解决方案

但实际业务中,我们可能需要请求不同服务器上的数据,此时我们就需要跨域请求。

  • JSONP

    前端代码示例:

    let script = document.createElement('script')
    
    // 在 URL 后指定一个回调函数
    script.src = 'http://www.domain.com/list?callback=handleCallback'
    document.head.appendChild(script)
    
    // 回调执行函数
    function handleCallback(res) {
      console.log(res)
    }
    复制代码

    后端代码(node.js)示例:

    const querystring = require('querystring')
    const http = require('http')
    const server = http.createServer()
    
    server.on('request', function (req, res) {
      const params = qs.parse(req.url.split('?')[1])
      const fn = params.callback
    
      // jsonp返回设置
      res.writeHead(200, { 'Content-Type': 'text/javascript' })
      res.write(fn + '(' + JSON.stringify(params) + ')')
    
      res.end()
    })
    
    server.listen('8080')
    console.log('Server is running at port 8080...')
    复制代码
  • 跨域资源共享(CORS)

    前端设置:

    // 前端设置是否带 cookie,不携带则不需要设置
    xhr.withCredentials = true
    复制代码

    后端设置:

    {
      // 允许携带 cookie
      'Access-Control-Allow-Credentials': 'true',
      // 指定域名或使用通配符 *
      'Access-Control-Allow-Origin': 'http://www.domain.com',
    }
    复制代码
  • Webpack 代理

    module.exports = {
      devServer: {
        proxy: {
          '/api': { // 接口前缀
            target: 'http://www.domain.com', // 指定服务器地址
          },
        },
      },
    }
    复制代码
文章分类
前端
文章标签