encodeURI、new URL、btoa() 和 atob()

编程语言
0 449

掌握 Web API 中常用的编码和解码技术:encodeURI、encodeURIComponent、new URL、btoa() 和 atob()


encodeURI 和 encodeURIComponent
  • encodeURI 和 encodeURIComponent 是 JavaScript 中用于对URL进行编码的内置函数,它们的主要目的是将特殊字符编码为适合传输的格式

相同点:

  • 它们都会将非 ASCII 字符,以及某些 ASCII 字符(如空格)编码为 UTF-8,然后以 URL 编码的形式(即%加上两个十六进制数字)输出

不同点:

  • encodeURI 用于编码整个URI,它不会对 URI 中具有特殊含义的字符进行编码,例如冒号(:)、正斜线(/)、问号(?)和井号(#)等
  • encodeURIComponent 用于编码 URI 中的组成部分,它将编码所有非字母数字字符,包括某些在某些URI组件中具有特殊含义的字符

所以:如果需要对整个 URI 进行编码,应该使用 encodeURI() 方法;如果需要对查询字符串参数进行编码,应该使用 encodeURIComponent() 方法

  • 例如 https://www.baidu.com/index.html?go=abc
  • https://www.baidu.com/index.html 使用 encodeURL go 和 abc 都可以使用 encodeURLComponent
const url = 'http://example.com/path/to/page?name=小明&age=18'

const search = url.split('?')[1]
const params = {}
search.split('&').forEach(param => {
	const [key, value] = param.split('=')
	params[key] = value
})

const encodedName = encodeURIComponent(params.name)
const encodedAge = encodeURIComponent(params.age)

const encodeSearchParams = `http://example.com/path/to/page?name=${encodedName}&age=${encodedAge}`
const encodeUrl = encodeURI(url)

// 编码后如果想得到原始字符串可以使用 decodeURI 和decodeURIComponent 解码
console.log(decodeURIComponent(encodeSearchParams))
console.log(decodeURI(encodeUrl))
new URL
  • URL 是 JavaScript 中用于处理 URL 的内置对象,它提供了一系列方法和属性,方便我们对 URL 进行解析和操作

我们可以使用 new URL() 构造函数创建 URL 对象并访问其属性方法:

const url = new URL('https://www.example.com/path/file?query=value#fragment')
console.log(url.protocol) // 输出:https:
console.log(url.host) // 输出:www.example.com
console.log(url.pathname) // 输出:/path/file
console.log(url.search) // 输出:?query=value
console.log(url.hash) // 输出:#fragment

URL 对象还提供了一些方法,例如 toString() 方法可以将 URL 对象转换为字符串,searchParams 属性可以访问查询字符串参数等:

const url = new URL('https://www.example.com/path/file?name=张三&age=20')

console.log(url.searchParams.get('name')) // 张三
console.log(url.searchParams.get('age')) // 20

// 下面这种形式也能获取 search
const params = new URLSearchParams(location.search)
const name = params.get('name')
const age = params.get('age')

url.pathname = '/new/path'

console.log(url.toString()) // https://www.example.com/new/path?name=%E5%BC%A0%E4%B8%89&age=20

更多方法:

  • keys()    返回iterator,此对象包含所有搜索的键名
  • values()   返回iterator,此对象包含所有的value
  • entries()    返回一个iterator,可以遍历所有的键值对的对象
  • set()     设置一个搜索参数新值,原来有多个值将删除其他所有值
  • get()     获取指定搜索参数的值
  • has()   判断是否有指定的搜索参数
  • getAll()   获取指定搜索参数的所有值,返回一个数组
  • delete()   从搜索参数列表里删除指定的键和值
  • append()  插入一个指定的键/值
  • toString()   返回搜索参数组成的字符串
  • sort()  按键名排序
btoa() 和 atob()
  • toa() 和 atob() 是 JavaScript 中用于 Base64 编码和解码的方法

btoa() 方法用于将字符串转换为 Base64 编码。它接受一个字符串作为参数,返回一个 Base64 编码的字符串。例如:

const str = 'Hello world'
const encodedStr = btoa(str)

console.log(encodedStr) // SGVsbG8gd29ybGQ=

atob() 方法用于将 Base64 编码的字符串解码为原始字符串。它接受一个 Base64 编码的字符串作为参数,返回一个原始字符串。例如:

const encodedStr = 'SGVsbG8gd29ybGQ='
const str = atob(encodedStr)
console.log(str) // Hello world

需要注意的是,btoa() 和 atob() 方法只能处理 ASCII 字符串(包含 128 个字符,其中包括英文字母、数字、标点符号和一些控制字符),如果字符串中包含非 ASCII 字符,需要先将其转换为 UTF-8 编码的字节数组,再进行 Base64 编码。例如

const str = '你好 世界'
const utf8Bytes = new TextEncoder().encode(str)
const encodedStr = btoa(String.fromCharCode(...utf8Bytes))
console.log(encodedStr) // 5L2g5aW9IOS4lueVjA==

同样地,如果需要将 Base64 编码的字符串解码为非 ASCII 字符串,需要先将其解码为字节数组,再将字节数组转换为字符串。例如:

let encodedStr = '5L2g5aW9IOS4lueVjA=='
let bytes = new Uint8Array(
  atob(encodedStr)
    .split('')
    .map(c => c.charCodeAt(0))
)
let str = new TextDecoder().decode(bytes)
console.log(str) // 你好 世界

应用场景:

  1. 图片或音频的 Base64 编码

在前端开发中,经常需要将图片或音频等二进制数据转换为 Base64 编码的字符串,以便在网页中直接显示或传输

可以使用 btoa() 方法将二进制数据编码为 Base64 字符串,例如:

// 通过fetch方法获取远程服务器上的图片文件,并将响应结果转换为Blob对象
const blob = await fetch('example.png').then(res => res.blob());

// 创建一个Promise对象,将Base64编码后的图片数据存储在变量base64中
const base64 = await new Promise(resolve => {
  // 创建一个FileReader对象,用于将Blob对象中的数据转换为Base64编码的字符串
  const reader = new FileReader();
  // 当FileReader对象读取完成时触发onload事件
  reader.onload = () => {
    // 将DataURL中的Base64编码字符串取出,并将其存储在变量base64中
    resolve(reader.result.split(',')[1]);
  };
  // 将Blob对象中的数据读取为DataURL
  reader.readAsDataURL(blob);
});
  1. API 的响应结果的 Base64 编码

某些API的响应结果可能包含二进制数据,例如图片或音频等,这些数据可以通过 btoa() 方法进行 Base64 编码,然后在网络传输中传递。例如:

// 使用fetch方法获取远程服务器上的图片文件example.png
fetch('example.png')
  // 将响应结果转换为ArrayBuffer对象
  .then(res => res.arrayBuffer())
  // 将ArrayBuffer对象转换为Base64编码字符串
  .then(buffer => {
    // 将ArrayBuffer对象转换为Uint8Array数组,便于后续处理
    const uint8Array = new Uint8Array(buffer);
    // 使用btoa方法将Uint8Array数组转换为Base64编码字符串
    const base64 = btoa(
      // 使用reduce方法将Uint8Array数组中的数据转换为ASCII字符串
      uint8Array.reduce((data, byte) => data + String.fromCharCode(byte), '')
    );
    // 将Base64编码后的字符串输出到控制台
    console.log(base64)
  });
  1. 安全地传输或存储二进制数据

由于 Base64 编码后的字符串只包含 ASCII 字符,因此可以安全地传输或存储到不支持二进制数据的地方(如URL、XML等),以避免出现数据传输或存储时的格式问题。例如:

// 创建一个Uint8Array数组,包含 ASCII 编码的字符串"Hello World"
const data = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64]);

// 将Uint8Array数组转换为Base64编码字符串
const base64 = btoa(
  // 使用reduce方法将Uint8Array数组中的数据转换为ASCII字符串
  data.reduce((data, byte) => data + String.fromCharCode(byte), '')
);

// 将Base64编码后的字符串作为查询字符串的值,拼接成完整的URL
const url = `https://example.com/api?data=${encodeURIComponent(base64)}`

要注意的是,由于 Base64 编码后的字符串通常比原始二进制数据大约33%,因此在传输或存储大量二进制数据时,需要考虑编码后的数据大小问题,以免影响性能。