前言:大家好,我是忆白,本文根据慕课网双越老师《一天时间迅速准备前端面试 快速构建初级前端知识体系》课程整理的面试常考题目以及相应知识扩展,持续更新。
1. http常见的状态码有哪些?
1.1 状态码分类
- 1xx 服务器收到请求
- 2xx 请求成功,如 200
- 3xx 重定向,如 302
- 4xx 客户端错误,如 404
- 5xx 服务端错误,如 500
1.2 常见状态码
- 200 成功
- 301 永久重定向(配合响应报文 location字段指定地址,浏览器自动处理)
- 302 临时重定向(配合响应报文 location字段指定地址,浏览器自动处理)
- 304 资源未被修改(表示可以继续用缓存中的文件)
- 404 资源未找到
- 403 没有权限
- 500 服务器错误
- 504 网关超时(服务器可能由多台机器组成,内部处理时,内部跳转可能超时)
2. 什么是Restful-API?
2.1 传统的 methods
- get 获取服务器的数据
- post 向服务器提交数据
- 简单的网页功能,就这两个操作
2.2 现在的 methods
- get 获取数据
- post 新建数据
- patch/put 更新数据
- delete 删除数据
2.3 Restful API
- 一种新的 API 设计方法(早已推广使用)
- 传统 API 设计:把每个 url 当作一个功能
- Restful API 设计:把每个 url 当作一个唯一的资源
2.4 如何设计成一个资源?
1、尽量不使用 url 参数
- 传统 API 设计:/api/list?pageIndex=2
- Restful API 设计:/api/list/2
2、用method表示操作类型
-
传统API设计:
- post请求 /api/create-blog
- post请求 /api/update-blog?id=100
- get请求 /api/get-blog?id=100
-
Restful API 设计:
- post请求 /api/blog (创建一个blog数据)
- patch/put请求 /api/blog/100 (更新blog/100数据)
- get 请求 /api/blog/100 (获取/blog/100数据)
3. http有哪些常见的header?
3.1常见的 Request Headers
- Accept 浏览器可接收的数据格式
- Accept-Encoding 浏览器可接收的压缩算法,如 gzip
- Accept-Language 浏览器可接受的语言,如 zh-CN
- Connection:keep-alive 一次 TCP 连接重复使用
- cookie
- Host 请求的域名
- User-Agent(简称 UA)浏览器信息
- Content-type 发送数据的格式,如 application/json
3.2 常见的 Response Headers
- Content-type 返回数据的格式,如 application/json
- Content-length 返回数据的大小,多少字节
- Content-Encoding 返回数据的压缩算法,如 gzip
- Set-Cookie 用于服务端设置Cookie
3.3 缓存相关的 headers
- Cache-Control Expires
- Last-Modified If-Modified-Since
- Etag If-None-Match
4. http 缓存
4.1 什么是缓存?
第一次打开一个网站之后,服务端会返回所有资源,但当之后再访问的时候,有些资源未改变,不需要再向服务端获取,这些资源就是缓存。
4.2 为什么需要缓存
网络请求相对于CPU运算来说,是比较慢的,并且网络具有不确定性,通过缓存可以提高页面加载速度,提高用户体验。
4.3哪些资源可以被缓存?
静态资源(Js、css、img)
4.4 http缓存 —— 强制缓存
由服务端返回的响应头 cache-control 字段控制强制缓存
- max-age 单位秒,控制缓存可以持续多少秒
- no-cache 强制客户端每次都必须向服务器发送请求。服务器接收到请求判断资源是否变更,是则返回新内容,否则返回304表示未变更。
4.5 http 缓存——协商缓存(对比缓存)
- 服务器端缓存策略(服务端判断这个资源是否可以做缓存)
- 服务端判断客户端资源,是否和服务端资源一样
- 一致则返回304,否则返回200和最新的资源
4.6 两种标识资源的方式
资源标识(在 Response Headers 中,有两种):
- Last-Modified 资源的最后修改时间
请求中If-Modified-Since的值就是初次请求返回的Last-Modified最后修改时间,服务器会根据If-Modified-Since与当前资源的最后修改时间做对比,一样则返回304,否则返回新的资源和新的最后修改时间Last-Modified。
- Etag 资源的唯一标识(一个字符串,根据文件内容计算出来的唯一字符串,类似人类的指纹,独一无二)
请求中If-None-Match的值就是初次请求返回的Etag最后修改时间,服务器会将If-None-Match和这个资源重新计算出来的Etag对比,如果资源未修改,则计算出来的Etag会和之前返回的Etag一样,返回304,否则返回新的资源和新的Etag。
协商缓存示例:
因为资源没变,第二次响应报文只需要返回304不需要携带资源,因此Size明显小了很多。
当Last-Modified和Etag头部字段共存时
- 会优先使用 Etag
- Last-Modifed只能精确到秒级
- 如果资源被重复生成,而内容不变,则 Etag 更精确。
4.7 http缓存综述
首先浏览器发出HTTP请求,假如有cache-control控制强制缓存,先根据max-age判断缓存是否过期
- 如果在规定时间内,没有过期,就会直接读取上一次缓存的资源。如果强制缓存过期了,那么就判断是否有Etag和Last-Modifed协商缓存字段,有的话就会带着If-None-Match,If-Modified-Since字段发送请求,然后服务器判断缓存是否可以继续使用。
- 如果可以使用,则返回304,浏览器继续读取缓存。
- 如果不可以使用,就会返回200和最新的资源。
- 如果没有Etag和Last-Modified协商缓存字段,那么会直接发起HTTP请求,请求最新的资源,然后服务器返回最新的资源。
4.8 刷新页面对http缓存的影响
-
正常操作:地址栏输入 url ,跳转链接,前进后退等
强制缓存和协商缓存都有效。
-
手动刷新:F5,点击刷新按钮,右击菜单刷新
强制缓存失效,协商缓存有效。
-
强制刷新:ctrl + F5
强制缓存和协商缓存都失效。
5. https
- http 是明文传输,敏感信息容易被中间劫持
- https = http + 加密,劫持了也无法解密
对称加密
- 对称加密:使用同一个 key 负责加密、解密
- 非对称加密:使用一对 key (公钥私钥),A 加密之后,只能用 B 来解密
- https 同时用到了这两种加密方式(先使用非对称加密,客户端使用公钥传递一个密钥,之后的通信使用这个密钥对称加密)
https 证书
-
中间人攻击
因为在浏览器派发公钥时,中间人可以劫持并用自己的公钥调换,这样客户端使用这个公钥加密后的密钥就能被中间人用自己的私钥解密出来
-
使用第三方证书(慎用免费、不合格的证书)
-
浏览器校验证书
详细可参考我另一篇文章:确保Web安全的HTTPS
6. 手写一个简易Ajax
通过 AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据。 Ajax核心是使用 XMLHttpRequest
对象。
6.1 open方法
open()
方法 用于初始化一个请求。open()方法接收三个参数:
method
:要发送的请求的类型。比如GET、POST、PUT、DELETE等。url
:请求的URL。async
:是否异步发送请求的布尔值。true为异步发送请求。
6.2 Ajax 请求的五种状态,readyState 属性
- 0:表示
XMLHttpRequest
实例已经生成。尚未调用open()
方法 - 1:表示 已经调用
open()
方法,但没有调用send()
方法,仍然可以使用setRequestHeader()
,设定 HTTP请求头信息。 - 2:表示
send()
方法已经执行,并且头信息和状态码已经收到。 - 3:表示正在接收服务器传来的 body 部分的数据。
- 4:表示服务器数据已经完全接收,或者本次接收已经失败了
function ajax ( url , successFn ){
const xhr = new XMLHttpRequest()
// true异步,避免卡住, false为同步
xhr.open( 'GET' , url , true)
// Ajax状态改变时的回调
xhr.onreadystatechange = function() {
if( xhr.readyState == 4 ){
if( xhr.status == 200 ){
successFn(xhr.responseText)
}
}
}
xhr.send(null)
}
复制代码
6.3 Ajax结合Promise封装
function ajax(url) {
const p = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open('GET', url, true)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
resolve(
JSON.parse(xhr.responseText)
)
} else if (xhr.status === 404) {
reject(new Error('404 not found'))
}
}
}
xhr.send(null)
})
return p
}
复制代码
7. 什么是跨域,为什么会产生跨域
浏览器存在一个同源策略的限制,跨域请求的响应返回时,浏览器会拦截掉。
同源策略:
- 发送请求时,浏览器要求请求的服务器的url必须和当前网站同源
- 同源:协议、域名、端口三者必须相同,有一个不同就违背同源策略
8. 如何解决跨域问题
所有的跨域,都必须经过server端允许和配合 未经server端允许就实现跨域,说明浏览器有漏洞,是一个危险信号。 常见解决跨域的方式有JSONP、CORS和代理跨域。
8.1 JSONP解决跨域的原理
在网页有一些标签天生具有跨域能力,比如:img、link、iframe、script。 JSONP 就是利用 script 标签的跨域能力来发送请求的。
-
动态创建一个
script
标签:var script=document.createElement("script");
-
设置src,传递一个callback参数abc,并提前定义好一个回调函数
script.src="http://localhost:3000/testAJAX?callback=abc"; functionabc(data){ alert(data.name); }; 复制代码
-
将 script 添加到 body 中
-
服务器中路由的处理,拿到callback参数,返回一个callback的调用,并将数据以参数形式传递进去
router.get("/testAJAX",function(req,res){ console.log("收到请求"); var callback=req.query.callback; var obj={ name:"孙悟空", age:18 } res.send(callback+"("+JSON.stringify(obj)+")"); }); 复制代码
-
这样,客户端就会加载到 abc({name:”孙悟空”, age:18})` 这样一段js脚本并执行,进而拿到服务器传递的参数,并在alert弹出,就解决了跨域问题
8.2 CORS
CORS(Cross-OriginResourceSharing),跨域资源共享。CORS 是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持get 和 post 请求。跨域资源共享标准新增了一组HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。
CORS 是通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会对响应放行。
router.get("/testAJAX",function(req,res){
//通过 res 来设置响应头,来允许跨域请求
//res.set("Access-Control-Allow-Origin","http://127.0.0.1:3000");
res.set("Access-Control-Allow-Origin","*");
res.send("testAJAX 返回的响应");
})
复制代码
8.3 代理服务器转发
因为同源策略只是浏览器的策略,在服务器之间并不存在,因此可以在客户端和要通信的服务器之间搭建一台代理服务器,这台代理服务器和客户端是同源的,因此我们可以把请求都发送给代理服务器,之后代理服务器帮我们把请求进行转发给目标服务器,这样就解决了跨域。在开发阶段,我们通常配置webpack中的devServer搭建代理服务器,上线通过Nginx配置代理服务器进行转发。
9. cookie、localStorage、sessionStorage的区别
区别:
- 存储大小:Cookie 4K、Storage 5M
- 有效期:Cookie拥有有效期,localStorage永久存储,sessionStorage存储在内存,浏览器关闭就没了。
- Cookie会随HTTP请求发送到服务器端,Storage只存储在浏览器端
- 路径:Cookie有路径限制,Storage只存储在域名下
写在最后
如果你觉得我写的还不错,可以给我点个赞哦,如果有写错的地方,也欢迎大家评论指出,谢谢。