HTTP/HTTPS
HTTP(超文本传输协议),是一种应用层协议,主要用于网络上客户端与服务器的通信,以获取和传输超文本数据。HTTP 通常运行在 TCP 之上。TCP(传输控制协议)是传输层协议,通过三次握手来建立两端可靠的连接。
HTTPS(安全超文本传输协议),是在 HTTP 基础上加入了 SSL/TLS 协议,提供了数据加密、安全性验证和身份验证,安全性更高。
简单罗列一下 http 的关键内容:
- http 方法:get/post/put/delete/patch/head/options。
- 状态码:2xx 成功,3xx 重定向,4xx 客户端错误,5xx 服务器错误。
- http 头:Authorization 等请求头,Content-Type 等响应头。
- 内容编码:服务器可以通过 gzip 等内容编码压缩响应数据。
- 跨站资源共享(CORS):通过 Access-Control-Allow-Origin 限制可访问名单。
- 缓存控制:Cache-Control 允许服务器控制资源的缓存行为。
- 连接管理:HTTP/1.1 默认使用持续连接(Connection: keep-alive)。HTTP/2 引入了多路复用。
- 分快传输:http 可以使用分块传输编码,不需要服务器知道内容长度。
XMLHttpRequest
2005 年,Ajax 技术被专门提出,这项技术能够实现在不刷新浏览器的情况下,实现服务器请求。其关键技术是 XMLHttpRequest 对象,XMLHttpRequest 对象比 Ajax 的历史更长。
这是 XMLHttpRequest 的一个基本使用示例:
let xhr = new XMLHttpRequest();
xhr.onload = function (event) {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
};
xhr.onprogress = function (event) {
let divStatus = document.getElementById("status");
if (event.lengthComputable) {
divStatus.innerHTML =
"Received " + event.position + " of " + event.totalSize + " bytes";
}
};
xhr.timeout = 1000; // 设置 1 秒超时
xhr.ontimeout = function () {
alert("Request did not return in a second.");
};
xhr.onerror = function() {
console.log('An error occurred during the request.');
};
xhr.open("get", "altevents.php", true);
let form = document.getElementById("user-info");
xhr.send(new FormData(form));
encodeURICompanent 与 DecodeURI
encodeURICompanent
encodeURIComponent 是 JavaScript 中的一个函数,用于编码一个 URI 的组成部分。在 URI 中,某些符号具有特殊意义,如冒号:、正斜杠/、问号?、井号#、空格等,如果直接将这些字符插入到 URI 中,会导致 URI 无法解析。encodeURIComponent 会将字符串中所有非字母数组字符(除了-、_、.、~等)都转为百分号编码。
一个为 get 请求添加参数的方法,基于 encodeURIComponent() 方法封装:
function addURLParam(url, name, value) {
url += url.indexOf("?") == -1 ? "?" : "&";
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
return url;
}
DecodeURI
decodeURI 则是对整个 URI 进行编码,并且只编码影响 URI 结构的字符。
使用场景
- 构建查询参数与请求数据:确保服务器正确解析请求。
- 避免 XSS 攻击:编码后的特殊字符不会被浏览器作为代码执行。
- 处理 URL 国际化:确保 URL 在各种环境下正常处理和显示。
- 分享链接:分享的连接不会因为特殊字符导致错误。
URI 与 URL
URI(Uniform Resource Identifier)和URL(Uniform Resource Locator)是互联网上用于标识资源的两种不同的概念,它们之间有着密切的关系,但也有一些区别:
- URI(统一资源标识符):
-
- URI是一种标准化的字符串,用于标识资源。资源可以是任何东西,比如文档、图片、视频、服务等。
- URI包括URL和URN(Uniform Resource Name)两种形式。
- URI的一般格式为:
scheme:[//[user:password@]host[:port]][/path][?query][#fragment]
。 - 例如,
http://www.example.com/index.html
是一个URI,其中http
是scheme,www.example.com
是host,index.html
是path。
- URL(统一资源定位符):
-
- URL是URI的一种,专门用于标识资源的位置,即资源在网络中的地址。
- URL提供了一种访问资源的方式,通过指定协议、服务器地址、路径等信息,可以直接访问到资源。
- URL是互联网上最常见的URI类型,大多数时候,当我们提到URI时,实际上指的是URL。
- 例如,
http://www.example.com/index.html
就是一个URL,它通过HTTP协议定位到了www.example.com
服务器上的index.html
文件。
- URN(统一资源名称):
-
- URN是URI的另一种形式,它通过名称来标识资源,而不是通过位置。URN的设计目的是提供一种持久的、位置无关的资源标识方式。
- URN的格式通常为:
urn:namespace:specific
,其中namespace
是命名空间的标识,specific
是该命名空间下的具体名称。 - 例如,
urn:isbn:0-395-36341-1
是一个URN,它标识了一个特定的ISBN号。
- 区别:
-
- URI是一个更广泛的概念,包括了URL和URN。
- URL是URI的一种,专门用于标识资源的位置。
- URN是URI的另一种形式,通过名称而不是位置来标识资源。
在实际应用中,URL是最常用的URI类型,因为它提供了一种直接访问资源的方式。URN虽然理论上提供了一种更持久的资源标识方式,但在实际应用中使用较少。
跨站资源共享
- CORS(cross-origin resource sharing)定义了浏览器与服务器如何实现跨源通信。请求头携带 Origin 参数,指请求发送的页面源;浏览器如果响应了,会在头部携带 Access-Control-Allow-Origin,这个参数可以是具体源,也可以是*,代表公开。
- 预检请求 options:当浏览器使用自定义头部(如Authorization、Content-Type: application/json)、非简单请求(不是 HEAD、GET、POST)或请求中使用了 XMLHttpRequestUpload 对象时,会触发预检请求。
-
- 请求内容: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:缓存预检请求的秒数。
- 跨域请求通过 withCredentials: true 来携带凭证(cookie、HTTP 认证信息、SSL 证书等)。
Fetch
- fetch 失败(触发 catch)的情况:请求发起错误(如违反 CORS、无网络、HTTPS 错配等)、超时。
- 其他情况都是通过 then 来处理,通过 status 来具体判断 200、404、500 等。
fetch 参数(与 Request 对象基本相同):
fetch({
body, // 指定使用请求体时请求体的内容
cache, // 控制浏览器与HTTP缓存的交互
credentials, // 用于指定在外发请求中如何包含 cookie
headers, // 用于指定请求头部,必须是 Headers 实例
integrity, // 用于强制子资源完整性
keepalive, // 用于指示浏览器允许请求存在时间超出页面生命周期
method, // 用于指定 HTTP 请求方法
mode, // 用于指定请求模式,cors 等
redirect, // 用于指定如何处理重定向响应(状态码为 301、302、303、307 或 308)
referrer, // 用于指定 HTTP 的 Referer 头部的内容
referrerPolicy, // 用于指定 HTTP 的 Referer 头部
signal, // 用于支持通过 AbortController 中断进行中的 fetch()请求
url, // 请求地址
})
Response 对象:
Response {
body: (...), // text/json/formData/arrayBuffer/blob
bodyUsed: false,
headers: Headers {}, // 响应包含的 Headers 对象
ok: true, // 布尔值,表示 HTTP 状态码的含义: 200-299
redirected: false, // 布尔值,表示响应是否至少经过一次重定向
status: 200, // 整数,表示响应的 HTTP 状态码
statusText: "OK", // 字符串,包含对 HTTP 状态码的正式描述
type: "default", // 字符串,包含响应类型: basic/cors/error等
url: "", // 包含响应 URL 的字符串
}
Web Socket
Web Socket(套接字)的目标是通过一个长时连接实现与服务器全双工、双向的通信。在 JavaScript 中创建 Web Socket 时,一个 HTTP 请求会发送到服务器以初始化连接。Web Socket 要使用 ws://和 wss:// 协议。
let socket = new WebSocket("ws://www.example.com/server.php");
socket.onopen = function () {
alert("Connection established.");
};
socket.onerror = function () {
alert("Connection error.");
};
socket.onclose = function () {
alert("Connection closed.");
};
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);
socket.onmessage = function (event) {
let data = event.data;
// 对数据执行某些操作
};
前端需关注的网络安全问题
敏感信息泄露
- 通过 httpOnly 等禁止 JavaScript 访问 cookie。
- 明文隐私数据进行脱敏处理。
- 使用 HTTPS 代替 HTTP,确保数据传输过程中的加密。
XSS 攻击(跨站脚本攻击)
- 对用户输入进行适当的过滤和转义,确保在输出到 HTML 页面时不会被作为代码执行。
- 使用内容安全策略(CSP)来限制加载和执行的资源,减少 XSS 攻击的风险。
- 验证上传文件的安全。
CSRF(跨站请求伪造)
- 使用 CSRF token,并在服务器验证,确认请求来自用户。
- 验证 HTTP referer 字段,确保请求来自合法来源。
- 设置合理的 cookie sameSite 属性,限制第三方 cookie 的使用。
CORS(跨站资源共享)滥用
- 设置可访问白名单。
权限限制
- 敏感资源需要添加授权及验证机制。