夜听城嚣 夜听城嚣
首页
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 前端基建与架构
  • 专题分享

    • Git入门与开发
    • 前端面试题汇总
    • HTML和CSS知识点
  • 项目实践
  • 抓包工具
  • 知识管理
  • 工程部署
  • 团队规范
bug知多少
  • 少年歌行
  • 青年随笔
  • 文海泛舟
  • 此事躬行

    • 项目各工种是如何协作的
    • TBA课程学习
收藏

dwfrost

前端界的小学生
首页
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 前端基建与架构
  • 专题分享

    • Git入门与开发
    • 前端面试题汇总
    • HTML和CSS知识点
  • 项目实践
  • 抓包工具
  • 知识管理
  • 工程部署
  • 团队规范
bug知多少
  • 少年歌行
  • 青年随笔
  • 文海泛舟
  • 此事躬行

    • 项目各工种是如何协作的
    • TBA课程学习
收藏
  • 第1章 什么是JavaScript
  • 第2章 HTML中的JavaScript
  • 第3章 语言基础
  • 第4章 变量、作用域与内存
  • 第5章 基本引用类型
  • 第6章 集合引用类型
  • 第7章 迭代器与生成器
  • 第8章 对象、类与面向对象编程
  • 第9章 代理与反射
  • 第10章 函数
  • 第11章 异步编程
  • 第12章 BOM
  • 第14章 DOM
  • 第15章 DOM扩展
  • 第16章 DOM2和DOM3
  • 第17章 事件
  • 第18章 动画与Canvas图形
  • 第19章 表单脚本
  • 第20章 JavaScript API
  • 第21章 错误处理与调试
  • 第23章 JSON
  • 第24章 网络请求与远程资源
    • 第25章 客户端存储
    • 第26章 模块
    • 第27章 工作者进程
    • 第28章 最佳实践
    • 《JavaScript高级程序设计》
    frost
    2022-04-22

    第24章 网络请求与远程资源

    前端有多种方式请求服务器资源,比如表单提交,ajax, fetch等方式。ajax的出现,让前端不需要刷新页面就可以局部更新页面数据,之后的jQuery和axios对其进行了封装和优化;而最新的fetch API则成为替代XHR,成为未来的网络请求方案。

    XMLHttpRequest(XHR)对象是实现ajax技术的关键,均已在各大浏览器实现。

    # XMLHttpRequest 对象

    # XHR使用

    实现原生的XHR方式如下:

    let xhr = new XMLHttpRequest()
    xhr.open('get', 'example.txt', false)
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4) {
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
          alert(xhr.responseText)
        } else {
          alert('Request was unsuccessful: ' + xhr.status)
        }
      }
    }
    xhr.send(null)
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    • open():入参为请求类型("get"、"post"等)、请求 URL,以及表示请求是否异步的布尔值。
    • send():入参只有一个,作为请求体发送的数据。如果没有,必须传null。
    • readyStat:表示当前处在请求/响应过程的哪个阶段。4为接收完成。
    • status:响应的 HTTP 状态。
    • responseText:响应体返回的文本。

    在收到响应之前如果想取消异步请求,可以调用 abort()方法:

    xhr.abort(); 
    
    1

    # HTTP头部

    包括请求头和响应头2种。

    默认请求头如下:

    • Accept:浏览器可以处理的内容类型。

    • Accept-Charset:浏览器可以显示的字符集。

    • Accept-Encoding:浏览器可以处理的压缩编码类型。

    • Accept-Language:浏览器使用的语言。

    • Connection:浏览器与服务器的连接类型。

    • Cookie:页面中设置的 Cookie。

    • Host:发送请求的页面所在的域。

    • Referer:发送请求的页面的 URI。

    • User-Agent:浏览器的用户代理字符串。

    可以通过setRequestHeader()方法设置自定义头部,如token。

    可以使用 getResponseHeader()方法和getAllResponseHeaders()从 XHR 对象获取响应头部。

    # GET请求

    • 用于向服务器查询某些信息。
    • 查询字符串必须使用encodeURIComponent()编码,key/value使用&分隔。
    • 请求数据是查询字符串格式
    • 由于浏览器url长度限制,get请求参数有长度限制。
    • 响应快,性能好

    # POST 请求

    • 用于向服务器发送应该保存的数据,数据通过请求体携带。
    • 请求数据可以是任意格式,且无大小限制。
    • 占用资源多,响应慢

    # XMLHttpRequest Level 2

    1. FormData 类型

      let data = new FormData(); 
      data.append("name", "Nicholas");
      
      1
      2

      XHR 对象能够识别作为 FormData 实例传入的数据类型并自动配置相应的头部。

    2. 超时

      timeout 属性设置了一个时间且在该时间过后没有收到响应时,XHR 对象就会触发 timeout 事件。

    3. overrideMimeType()方法

      overrideMimeType()方法用于重写 XHR 响应的 MIME 类型。响应返回的 MIME 类型决定了 XHR 对象如何处理响应。比如服务器实际发送了 XML 数据,但响应头设置的 MIME 类型是 text/plain。此时浏览器拿到的是文本,就当成文本来处理了。可以设置为xhr.overrideMimeType("text/xml");将其设置为XML处理。

    # 进度事件

    有 6 个进度相关的事件。

    • loadstart:在接收到响应的第一个字节时触发。

    • progress:在接收响应期间反复触发。

    • error:在请求出错时触发。

    • abort:在调用 abort()终止连接时触发。

    • load:在成功接收完响应时触发,用于替代readystatechange事件。

    • loadend:在通信完成时,且在 error、abort 或 load 之后触发。

    # 跨源资源共享

    即CORS 背后的基本思路就是使用自定义的 HTTP 头部允许浏览器和服务器相互了解,以确实请求或响应

    应该成功还是失败。

    如果服务器决定响应请求,那么应该发送 Access-Control-Allow-Origin 头部,包含相同的源; 或者如果资源是公开的,那么就包含"*"。

    如果没有这个头部,或者有但源不匹配,则表明不会响应浏览器请求。

    在跨域的时候,默认情况下:

    • 不能使用 setRequestHeader()设置自定义头部。
    • 不能发送和接收 cookie。

    但实际是可以支持的,浏览器会通过OPTIONS请求进行验证。

    OPTIONS请求包含以下头部:

    • Origin:与简单请求相同。

    • Access-Control-Request-Method:请求希望使用的方法。

    • Access-Control-Request-Headers:(可选)要使用的逗号分隔的自定义头部列表。

    服务器响应头可以包含以下信息:

    • Access-Control-Allow-Origin:与简单请求相同。

    • Access-Control-Allow-Methods:允许的方法(逗号分隔的列表)。

    • Access-Control-Allow-Headers:服务器允许的头部(逗号分隔的列表)。

    • Access-Control-Max-Age:缓存预检请求的秒数。

    跨域携带cookie,可以withCredentials 属性设置为 true 来表明请求会发送凭据。如果服务器允许带凭据的请求,那么可以在响应中包含如下 HTTP 头部:

    Access-Control-Allow-Credentials: true 
    
    1

    其他可以跨域的手段有:图片探测、JSONP等。

    # Fetch API

    # 基本用法

    fetch(url,init)

    url: 资源URL

    init: 请求配置,包括请求头,请求体等,字段有

    • body:是 Blob、BufferSource、FormData、URLSearchParams、ReadableStream 或 String 的

      实例

    • cache:可能的值有default、no-store、reload、no-cache、force-cache、only-if-cached。

    • credentials:omit、same-origin(默认)、include。

    • headers:指定请求头部。

    • method:请求方法。

    • mode:可能的值有cors、no-cors、same-origin。

    • 其他字段,就不一一列举了。

    返回一个Promise实例。

    只要服务器返回了响应,fetch() 都会resolved。

    违反 CORS、无网络连接、HTTPS 错配及其他浏览器/网络策略问题都会rejected。

    fetch('https://qux.com').then((response) => console.log(response.url,response.status));
    
    1

    # 常见 Fetch 请求模式

    1. 发送 JSON 数据
    let payload = JSON.stringify({
      foo: 'bar',
    })
    let jsonHeaders = new Headers({
      'Content-Type': 'application/json',
    })
    fetch('/send-me-json', {
      method: 'POST', // 发送请求体时必须使用一种 HTTP 方法
      body: payload,
      headers: jsonHeaders,
    })
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    1. 在请求体中发送参数
    let payload = 'foo=bar&baz=qux'
    let paramHeaders = new Headers({
      'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
    })
    fetch('/send-me-params', {
      method: 'POST', // 发送请求体时必须使用一种 HTTP 方法
      body: payload,
      headers: paramHeaders,
    })
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    1. 发送文件
    let imageFormData = new FormData()
    let imageInput = document.querySelector("input[type='file'][multiple]")
    for (let i = 0; i < imageInput.files.length; ++i) {
      imageFormData.append('image', imageInput.files[i])
    }
    fetch('/img-upload', {
      method: 'POST',
      body: imageFormData,
    })
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    1. 中断请求
    let abortController = new AbortController(); 
    fetch('wikipedia.zip', { signal: abortController.signal }) 
     .catch(() => console.log('aborted!'); 
    // 10 毫秒后中断请求
    setTimeout(() => abortController.abort(), 10); 
    // 已经中断
    
    1
    2
    3
    4
    5
    6

    # Headers 对象

    Headers和Map很像

    let h = new Headers()
    let m = new Map()
    // 设置键
    h.set('foo', 'bar')
    m.set('foo', 'bar')
    // 检查键
    console.log(h.has('foo')) // true
    console.log(m.has('foo')) // true
    console.log(h.has('qux')) // false
    console.log(m.has('qux')) // false
    // 获取值
    console.log(h.get('foo')) // bar
    console.log(m.get('foo')) // bar
    // 更新值
    h.set('foo', 'baz')
    m.set('foo', 'baz')
    
    // 取得更新的值
    console.log(h.get('foo')) // baz
    console.log(m.get('foo')) // baz
    // 删除值
    h.delete('foo')
    m.delete('foo')
    // 确定值已经删除
    console.log(h.get('foo')) // undefined
    console.log(m.get('foo')) // undefined
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27

    并且Headers可以初始化对象。

    let seed = {foo: 'bar'}; 
    let h = new Headers(seed); 
    console.log(h.get('foo')); // bar
    
    1
    2
    3

    一个 HTTP 头部字段可以有多个值,而 Headers 对象通过 append()方法支持添加多个值。

    let h = new Headers()
    h.append('foo', 'bar')
    console.log(h.get('foo')) // "bar"
    h.append('foo', 'baz')
    console.log(h.get('foo')) // "bar, baz"
    
    
    1
    2
    3
    4
    5
    6

    # Request 对象

    Request 对象是获取资源请求的接口。可以通过构造函数的方式创建Request对象。

    let r = new Request('https://foo.com'); 
    console.log(r);
    
    1
    2

    有2种方式克隆Request对象。

    • 将 Request 实例作为 input 参数传给 Request 构造函数
    • 使用 clone()方法

    # Response 对象

    Response 对象是获取资源响应的接口。

    可以通过构造函数初始化 Response 对象

    let r = new Response(); 
    console.log(r); 
    // Response { 
    // body: (...) 
    // bodyUsed: false 
    // headers: Headers {} 
    // ok: true 
    // redirected: false 
    // status: 200 
    // statusText: "OK" 
    // type: "default" 
    // url: "" 
    // }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    # Beacon API

    许多分析工具收集页面信息后,一般是在用户离开页面时进行发送,也就是监听unload事件。但实际上,unload意味着页面销毁,之后的异步请求会被浏览器取消,导致信息发送失败。

    为此,W3C引入了Beacon API 。它是POST的语法糖,拥有以下特性:

    • sendBeacon()并不是只能在页面生命周期末尾使用,而是任何时候都可以使用。

    • 调用 sendBeacon()后,浏览器会把请求添加到一个内部的请求队列。浏览器会主动地发送队

    列中的请求。

    • 浏览器保证在原始页面已经关闭的情况下也会发送请求。

    • 状态 码、超时和其他网络原因造成的失败完全是不透明的,不能通过编程方式处理。

    -信标(beacon)请求会携带调用 sendBeacon()时所有相关的 cookie。

    # Web Socket

    Web Socket(套接字)的目标是通过一个长时连接实现与服务器全双工、双向的通信。

    协议为ws://和 wss://。ws可以跨域。

    # 连接

    let socket = new WebSocket("ws://www.example.com/server.php");
    
    1

    ws创建连接后可以通过readyState 属性获取当前连接状态:

    • WebSocket.OPENING(0):连接正在建立。

    • WebSocket.OPEN(1):连接已经建立。

    • WebSocket.CLOSING(2):连接正在关闭。

    • WebSocket.CLOSE(3):连接已经关闭。

    # 关闭

    可以调用close()关闭连接。

    socket.close();
    
    1

    # 发送消息

    let stringData = "Hello world!"; 
    let arrayBufferData = Uint8Array.from(['f', 'o', 'o']); 
    let blobData = new Blob(['f', 'o', 'o']); 
    socket.send(stringData); 
    socket.send(arrayBufferData.buffer); 
    socket.send(blobData);
    
    1
    2
    3
    4
    5
    6

    # 接收消息

    socket.onmessage = function(event) { 
     let data = event.data; 
     // 对数据执行某些操作
    };
    
    1
    2
    3
    4

    # 事件

    • open:在连接成功建立时触发。

    • error:在发生错误时触发。连接无法存续。

    • close:在连接关闭时触发。

    # 安全

    CSRF攻击,是指未授权系统可以访问资源。未授权系统会按照处理请求的服务器的要求伪装自己。

    如何验证请求发送者拥有对资源的访问权限:

    • 要求通过 SSL 访问能够被 Ajax 访问的资源。

    • 要求每个请求都发送一个按约定算法计算好的令牌(token)。

    以下手段对防护 CSRF 攻击无效:

    • 要求 POST 而非 GET 请求(很容易修改请求方法)。

    • 使用来源 URL 验证来源(来源 URL 很容易伪造)。

    • 基于 cookie 验证(同样很容易伪造)。

    #前端笔记
    上次更新: 2022/04/26, 08:07:21
    第23章 JSON
    第25章 客户端存储

    ← 第23章 JSON 第25章 客户端存储→

    最近更新
    01
    提交代码时修改commit消息
    04-09
    02
    如何快速定位bug
    02-20
    03
    云端web项目开发踩坑
    08-25
    更多文章>
    Theme by Vdoing | Copyright © 2021-2025 dwfrost | 粤ICP备2021118995号
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式
    ×