文章目录
-
- 一、URI的编码与解码
-
- [1.1 URI介绍](#1.1 URI介绍)
- [1.2 什么是encodeURI](#1.2 什么是encodeURI)
- [1.3 什么是encodeURIComponent](#1.3 什么是encodeURIComponent)
- [1.4 应用场景](#1.4 应用场景)
- [1.5 URI解码](#1.5 URI解码)
- [1.6 扩展:内置对象URL](#1.6 扩展:内置对象URL)
- 二、字符串的Base64编码与解码
-
- [2.1 ASCII字符编解码](#2.1 ASCII字符编解码)
- [2.2 非ASCII字符编解码](#2.2 非ASCII字符编解码)
一、URI的编码与解码
1.1 URI介绍
URI
指的是统一资源标识符 (Uniform Resource Locator),它是用来标识和定位互联网上的资源 (如网页、图片、文档等)的一种标识方式 ,它是一个广义的概念,如我们常用的URL
就属于URI
,URL
能够定位给到互联网上的某个资源的位置。它主要有两个子集:
-
URL
:用于标识和定位互联网上的资源的位置。它包括了资源的地址和访问方式 ,以确保资源能正常被定位和检索。通常由以下6部分组成。- 协议
protocol
:指定了资源的访问方式,常见的协议包括HTTP
、HTTPS
、FTP
、mailto
、file
等。 - 域名 (也叫主机名)
Host
:指定了资源所在的服务器或计算机的域名或IP
地址。 - 端口
Post
:端口是可选的,它指定了服务器上用于处理请求的端口号。如果未指定端口,通常会使用默认端口,如 HTTP 的默认端口是 80。 - 路径
Path
:指定了服务器上资源的位置,通常是一个文件路径或目录路径。路径以斜杠/
开头,如/images/pic.jpg
。 - 查询参数
Query
:查询参数允许传递额外的信息给服务器,通常以?
开头,参数之间用&
分隔,如?name=John&age=30
。 - 片段标识符 (在
location
对象中是hash
)Fragment
:用于指定资源中的特定位置,如文档内的锚点。
示例
URL
:https://www.example.com:8080/images/pic.jpg?name=John&age=30#section2
- 协议
-
URN
:用于标识资源的名称,而不关心资源的位置或如何访问它。URN 的目的是提供一个唯一的、永久的资源标识符。例如,ISBN(国际标准书号)就是一种 URN,它用于唯一标识图书,而不考虑图书的存储位置或如何获取它。
1.2 什么是encodeURI
encodeURI()
是JavaScript的一个内置函数,用于将字符串中的特殊字符进行编码,以便能够在URL中传递。
其中encodeURI
不会编码的特殊字符包括:【主要就是url
常见字符】
类型 | 包含 |
---|---|
非转义字符 | A-Z、a-z、0-9、_ 、. 、- 、! 、~ 、' 、( 、) |
保留字符 | : 、/ 、? 、= 、& (前面这些属于url 常见字符)、; 、, 、@ 、+ 、$ |
数字符号 | # (这个也属于url 常见字符) |
语法:encodeURI(URI)
:URI
是一个字符串,返回一个新字符串。
1.3 什么是encodeURIComponent
encodeURIComponent()
也是JavaScript的一个内置函数,同样用于将字符串中的特殊字符进行编码,以便能够在URL中传递 。与encodeURI()
相比它会编码更多的字符。
它不会编码的特殊字符只有:
类型 | 包含 |
---|---|
非转义字符 | A-Z、a-z、0-9、_ 、. 、- 、! 、~ 、' 、( 、) |
也就是说encodeURIComponent()
会对url
常见字符进行编码。
语法:encodeURIComponent(uriComponent)
:uriComponent
是一个string、number、boolean、null,undefined
或者任何 object
。在编码之前,uriComponent
参数会被转化为字符串。返回新字符串。
下面我们通过代码对比encodeURI
:
javascript
let url = "https://www.aaa.com/path?name=zhangsan&age=18#fragment1";
// 输出:https://www.aaa.com/path?name=zhangsan&age=18#fragment1
console.log(encodeURI(url));
// 输出:https%3A%2F%2Fwww.aaa.com%2Fpath%3Fname%3Dzhangsan%26age%3D18%23fragment1
console.log(encodeURIComponent(url));
可以明显看到encodeURIComponent
对ur
l常见字符进行了编码。
1.4 应用场景
1 输入内容编码
假设我们有一个搜索功能,用户可以输入关键字进行搜索。用户输入的关键字可能包含特殊字符,如空格、问号、和号等。为了将关键字作为 URL 参数传递给服务器,我们需要使用 encodeURIComponent
对其进行编码。
javascript
const userInput = "JavaScript 2a+ 学习?";
// 编码用户输入
const encodedKeyword = encodeURIComponent(userInput);
// 构建 URL
const searchURL = `https://example.com/search?keyword=${encodedKeyword}`;
console.log(searchURL); // https://example.com/search?keyword=JavaScript%202a%2B%20%E5%AD%A6%E4%B9%A0%3F
2 Ajax请求
在使用 JavaScript 进行 AJAX 请求时,encodeURIComponent
也非常有用。当使用 fetch
或 XMLHttpRequest
发送数据时,特别是发送 POST 请求时,需要确保请求体中的数据是经过编码的。
javascript
let data = {
username: "John Doe",
email: "john.doe@example.com",
};
// 将 JavaScript 对象转换为 URL 编码的字符串
const encodedData = Object.keys(data)
.map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`)
.join("&");
console.log(encodedData); // username=John%20Doe&email=john.doe%40example.com
fetch("https://example.com/submit", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: encodedData,
});
1.5 URI解码
使用decodeURI
和decodeURIComponent
可以解码
javascript
// 未编码的str: username=John Doe&email=john.doe@example.com
// 输出:username=John Doe&email=john.doe%40example.com
console.log(decodeURI('username=John%20Doe&email=john.doe%40example.com'));
// 输出:username=John Doe&email=john.doe@example.com
console.log(decodeURIComponent('username=John%20Doe&email=john.doe%40example.com'));
可以看到由于encodeURI
不能编码保留字符@
,因此decodeURI
也不能将@
对应的编码%40
转回@
。
1.6 扩展:内置对象URL
这里扩展一下内置对象URL。
我们可以使用 new URL() 构造函数创建 URL 对象并访问其属性方法,类似于location
,URL 对象还提供了一些方法,例如searchParams
属性可以访问查询字符串参数等。
javascript
const url = new URL("https://www.aaa.com/path?name=zhangsan&age=18#fragment1");
console.log(url.protocol); // https: 协议
console.log(url.host); // www.aaa.com 域名
console.log(url.port); // 端口
console.log(url.pathname); // /path 路径
console.log(url.search); // ?name=zhangsan&age=18 query
console.log(url.hash); // #fragment1 hash
console.log(url.origin); // https://www.aaa.com origin
// 获取参数
console.log(url.searchParams.get("name")); // zhangsan
// 下面这种形式也能获取参数
const params = new URLSearchParams(url.search)
console.log(params.get('name')) // zhangsan
二、字符串的Base64编码与解码
由于 Base64
编码后的字符串只包含 ASCII
字符 ,因此可以安全地传输或存储到不支持二进制数据的地方(如URL、XML等),以避免出现数据传输或存储时的格式问题。
toa()
和 atob()
是 JavaScript 内置的用于 Base64
编码和解码的方法。
2.1 ASCII字符编解码
btoa()
方法用于将字符串转换为 Base64
编码。它接受一个字符串作为参数,返回一个 Base64
编码的字符串。例如:
ASCII字符编码为Base64
javascript
const str = 'Hello world'
const encodedStr = btoa(str)
console.log(encodedStr) // SGVsbG8gd29ybGQ=
atob()
方法用于将Base64
的字符串转换为原始字符串,如下:
解码
javascript
const encodedStr = 'SGVsbG8gd29ybGQ='
const str = atob(encodedStr)
console.log(str) // Hello world
2.2 非ASCII字符编解码
需要注意的是,btoa()
和 atob()
方法只能处理 ASCII
字符串(包含 128 个字符,其中包括英文字母、数字、标点符号和一些控制字符),如果字符串中包含非 ASCII
字符(如中文文字),需要先将其转换为UTF-8
编码的字节数组,再进行 Base64
编码。例如:
非ASCII字符编码Base64
javascript
const str = "你好 世界";
// TextEncoder构造函数接受码位流作为输入,并提供 UTF-8 字节流作为输出
const utf8Bytes = new TextEncoder().encode(str); // 转成utf8编码的字节数组
const encodedStr = btoa(String.fromCharCode(...utf8Bytes)); // 编码为base64编码的ASCII字符串
console.log(encodedStr); // 5L2g5aW9IOS4lueVjA==
解码
javascript
const decodedBytes = atob('5L2g5aW9IOS4lueVjA==').split('').map(char => char.charCodeAt(0)) // 转成utf8编码的字节数组
// TextDecoder接受一个ArrayBuffer、TypedArray或包含要解码的编码文本的对象,返回解码后的字符串。
const decodedStr = new TextDecoder().decode(new Uint8Array(decodedBytes)) //
console.log(decodedStr) // 你好 世界
应用场景:
在前端开发中,经常需要将图片或音频等二进制数据转换为 Base64 编码的字符串,以便在网页中直接显示或传输。
下面代码实现了将图片资源转成base64
格式。
javascript
async function mediaToBase64(filePath) {
// 将图片资源转成blob格式
const blob = await fetch(filePath).then((res) => res.blob());
// 创建一个Promise对象,将Base64编码后的图片数据存储在变量base64中
const base64 = await new Promise((resolve) => {
// 创建一个FileReader对象,用于将Blob对象中的数据转换为Base64编码的字符串
const reader = new FileReader();
// 当FileReader对象读取完成时触发onload事件
reader.onload = () => {
console.log(reader.result); // data:image/png;base64,base64字符串....
// 将DataURL中的Base64编码字符串取出,并将其存储在变量base64中
resolve(reader.result.split(",")[1]);
};
// 将Blob对象中的数据读取为DataURL
reader.readAsDataURL(blob);
});
return base64; // 返回的是一个promise对象 所以接受结果的时候需要.then拿到res
}
mediaToBase64("./img.png").then((res) => {
console.log(res); // base64字符串....
});
要注意的是,由于 Base64
编码后的字符串通常比原始二进制数据大约33%,因此Base64
格式只适合传输小量数据。
参考博客: