美文网首页
从 AJAX 到跨域问题

从 AJAX 到跨域问题

作者: 梧桐月明中 | 来源:发表于2020-08-28 18:15 被阅读0次

    本文目前为止只是个概述笔记,原文是个系列文章,链接在最后的参考部分,写得非常好,强烈推荐。

    AJAX 是什么

    Asynchronous JavaScript And XML

    xml 和 json

    • 最初互联网数据都是通过 xml(可扩展标记语言)传输的
    • 后来 json 巨多,json 只是数据
    • xml 是语言,依旧有自己的优势场景

    目的 -> 无页面刷新获取服务端数据

    是一种混合技术 -> JS、客户端、服务端

    • JS,用于获取数据后以操作 DOM 或其它方式达成目标
    • 客户端(即浏览器),提供 XMLHttpRequest 对象
    • 服务端,拥有允许客户端向其发起 AJAX 请求的相关设置

    使用 AJAX

    怎样通过 JS 发送 AJAX 请求?

    核心:XMLHttpRequest 对象 (构造函数)

    方法

    • .open() 准备启动一个 AJAX 请求
    • .setRequestHeader() 设置请求头部信息
    • .send() 发送 AJAX 请求
    • .getResponseHeader() 获取响应头部信息
    • .getAllResponseHeader() 获取一个包含所有响应头部信息的长字符串
    • .abort() 取消异步请求

    属性

    • .responseText 响应返回的主体文本
    • .responseXML 响应内容类型为 text/xmlapplication/xml 时,该属性包含响应返回的 XML DOM 文档
    • .status 响应的 HTTP 状态
    • .statusText HTTP 状态的说明
    • .readyState 表示“请求/响应”过程的当前活动阶段

    监听事件

    • .onreadystatechange() 监听 readyState 的变化

    使用流程?

    准备 open()

    • get/post
    • url ,查询参数
      注意:参数的名和值都需要 encodeURIComponent 进行编码
      注意:若 url 为相对地址,应该是相对于执行此代码的页面
    • 同步/异步

    设置请求头

    • 默认的请求头
    • setRequestHeader()
      注意部分浏览器不允许重写默认的请求头,因此自定义请求头是比较安全的做法

    发送数据

    • get -> send(null) 注意:send 必须有参数,所以需要传个 null
    • post -> send(data)

    处理响应

    • 异步 onreadystatechange readystate 0/1/2/3/4
    • 注意,事件处理函数写在 .open() 前(以保证浏览器兼容性)

    取消异步请求

    • xhr.abort()
    • 注意,取消后要手动给 xhr 解绑(xhr = null)以释放内存

    XMLHttpRequest 二级

    在之前的基础上,W3C 提出了 XMLHttpRequest 二级规范,但是并不是所有浏览器都实现了,介绍一些被全部或多数浏览器实现的功能。

    FormData 类型

    超时设定

    • timeout
    • ontimeout
    • 注意,超时后请求中止,会调用 ontimeout,但此时有可能 readyState 已经变为4,这意味着会继续调用 onreadystatechange,但是当超时请求中止后再访问 status 属性浏览器会报错误,因此需要将检查 status 的语句放入 try catch 中

    overrideMimeType() 方法

    进度事件

    • onloadstart
    • onprogress
    • onerror
    • onabort
    • onload
    • onloadend

    跨域问题

    缘起?同源策略

    AJAX 使数据传输变得方便,但是对于某些数据,隐私和安全需要重视,因此有了同源策略,来进行能力限制。

    浏览器的同源策略:限制不同之间执行特定操作

    • 一个源由协议、域名和端口三部分组成,三者中任一一个不同,都会被浏览器认为是不同的源。
    • 特定的操作是指:
      • 读取 Cookie、LocalStorage 和 IndexDB
      • 获取 DOM 元素
      • 发送 AJAX 请求

    为什么要限制这些特定操作

    • 很多网站会把用户名密码之类的数据存放到 Cookie,如果没有同源策略,我们就可以通过 JS 脚本读取到浏览器里存储的所有网站的 Cookie,有了同源策略,我们只能读取到自己的网站域名下的 Cookie,相当于只能读取自己设置的。
    • 如果能够获取其它源下的 DOM,那么利用 iframe 标签引入其它网站内容,诱导用户操作表单,由于能够获取其它站点的 DOM,就可以监听和操作 DOM,例如可以获取用户输入的密码。
    • 为什么要禁止发送 AJAX 请求呢?这和 Cookie 的运作原理有关。每一条 Cookie 都由 domain 和 path 两个属性来标识它所属的源,当浏览器发送 Http 请求时,它会自动查找与请求 URL 匹配的 Cookie,如果有,就会自动加入到 header 头的 Cookie 属性中发送出去,服务器返回信息,会原封不动地把这个 Cookie 内容加到返回头里传回来。嗅到危险了吗?如果没有同源策略,我们在自己的服务器上托管网站 A,在 A 网站被访问时,运行我们的脚本,脚本向 B 网站(比如是个银行网站)发送一个请求,如果这个用户的浏览器恰好保存有 B 网站的 Cookie,那么我们就可以通过请求的返回头拿到这个 Cookie 了。

    同源策略的表现

    • JS 读取 Cookie 等只能读到自己所在域的数据。
    • iframe 标签里只显示一个空空的 #document 节点。
    • 对于跨域的 AJAX 请求,在响应返回时,浏览器识别出来给拦下,只报个错误出来告诉跨域了。

    跨域解决方案

    (一)JSONP - 野路子出身却异常好用

    • JSON with padding,包裹的 json
    • 原理就是不用 AJAX 了,用 script 标签来达到目的。script 标签不受跨域限制,加载进来的脚本就会立即执行。怎么实现呢?来看客户端的用法:
    function handleResponse(response){
      alert(`You got the response data: ${response}`)
    }
    const script = document.createElement('script')
    script.src = 'http://somesite.com/json/?callback=handleResponse'
    document.body.insertBefore(script, document.body.firstChild)
    
    • 是不是迷惑了?response 到底是怎样拿到的?别急,关键的部分就在服务器了:服务器识别 url 解析出 callback 的函数名 handleResponse,然后把需要返回的 json 数据作为参数传入 handleResponse,把执行这个函数语句作为响应返回给浏览器。
    • 浏览器加载到这个脚本后直接执行,就弹出了 response 的内容了。
    • 是不是很巧妙呢,JSONP,这个 padding 原来就是我们的 callback 函数。

    (二)CORS - 官方推荐的跨域资源共享方案

    (坑,待填)

    (三)使用 HTML5 API:postMessage

    (坑,待填)

    (四)抛弃 HTTP,使用:Web Sockets

    (坑,待填)


    参考

    再也不学AJAX了!(一)AJAX概述
    再也不学AJAX了!(二)使用AJAX
    再也不学AJAX了!(三)跨域获取资源 ① - 同源策略
    再也不学AJAX了!(三)跨域获取资源 ② - JSONP & CORS
    再也不学AJAX了!(三)跨域获取资源 ③ - WebSocket & postMessage

    相关文章

      网友评论

          本文标题:从 AJAX 到跨域问题

          本文链接:https://www.haomeiwen.com/subject/mlmajktx.html