包括内容:
一. 计算机网络、HTML、浏览器相关
二. CSS相关
三. js相关
四.前端性能优化点
五.前端整体框架体系学习
(1)http和https的基本概念
http: 超文本传输协议,是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。
https: 是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
https协议的主要作用是:建立一个信息安全通道,来确保数组的传输,确保网站的真实性。
区别:http传输的数据都是未加密的,也就是明文的,网景公司设置了SSL协议来对http协议传输的数据进行加密处理,简单来说https协议是由http和ssl协议构建的可进行加密传输和身份认证的网络协议,比http协议的安全性更高。
tcp采用三次握手建立tcp连接,tcp连接建立之后就可以在这个连接上传输数据了。
(1)TCP是面向连接的,udp是无连接的即发送数据前不需要先建立链接。
(2)TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付。 并且因为tcp可靠,面向连接,不会丢失数据因此适合大数据量的交换。
(3)TCP是面向字节流,UDP面向报文,并且网络出现拥塞不会使得发送速率降低(因此会出现丢包,对实时的应用比如IP电话和视频会议等)。
(4)TCP只能是1对1的,UDP支持1对1,1对多。
(5)TCP的首部较大为20字节,而UDP只有8字节。
(6)TCP是面向连接的可靠性传输,而UDP是不可靠的。
WebSocket是HTML5中的协议,支持持久连续,
websocket建立的是长连接,在一个会话中一直保持连接;而ajax是短连接,数据发送和接受完成后就会断开连接。对于服务器与客户端的双向通信,WebSocket简直是不二之选.但是,很大一部分AJAX的使用场景仍然是传统的请求-响应形式,比如获取json数据、post表单之类。另外还有一种情况,也就是传输大文件、图片、媒体流的时候,最好还是老老实实用HTTP来传。
WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。多了下面2个属性:
Upgrade:webSocket;
Connection:Upgrade;
//告诉服务器发送的是websocket
websocket: var monitor = new WebSocket(“ws://”+ip+path) onOpen()、onMessage()、onClose()
在客户端中使用很简单,只需要开启一个 WebSocket 服务并且实现监听服务器发送的消息即可。
// 开启WebSocket服务
var ws = new WebSocket("ws://127.0.0.1:8001");
//进行监听连接成功,触发,当与服务器端建立websocket连接成功之后就会执行
ws.onopen = function (data) {
// 发送信息
ws.send("hello World");
};
ws.onmessage = function (data) {
console.log(data.data); // 接收信息
};
//当一个 WebSocket 连接被关闭时触发。也可以通过 onclose 属性来设置。
ws.onclose = function (data) {
console.log("关闭", data); //关闭
};
如上代码,我们可以使用 ws.send()发送数据,也可以适用 ws.onmessage (其实也可以使用ws.addEventListener(“message”,()=>{})进行监听)监听服务器端发送的信息数据,实现简单的实时双向传输功能。
在服务器端进行关闭当前链接。
两个可选参数:
*WebSockets 的CloseEvent 会在连接关闭时发送给使用 WebSockets 的客户端。它在 WebSocket 对象的 onclose 事件监听器中使用。服务端发送的关闭码,以下为已分配的状态码。正常关闭是返回状态码1000
head:类似于get请求,只不过返回的响应中没有具体的内容,用户获取报文头
options:允许客户端查看服务器的性能,比如说服务器支持的请求方式等等。
简而言之,OPTIONS请求方法的主要用途有两个:
1、获取服务器支持的HTTP请求方法;
2、用来检查服务器的性能。
即网页品质,就是指为了满足那些残障人士而设计的网站,比如网页可以调节字体大小,图片如果发生错误显示不出可以使用alt属性来描述图片
Bom是浏览器对象。有哪些常用的Bom属性呢?
(1)location对象
Location 对象是 Window 对象的一个部分,可通过 window.location 属性来访问。
location.href-- 返回或设置当前文档的URL location.search – 返回URL中的查询字符串部分。例如 http://www.dreamdu.com/dreamdu.php?id=5&name=dreamdu 返回包括(?)后面的内容?id=5&name=dreamdu location.hash – 返回URL#后面的内容,如果没有#,返回空 location.host – 返回URL中的域名部分,例如www.dreamdu.com location.hostname – 返回URL中的主域名部分,例如dreamdu.com location.pathname – 返回URL的域名后的部分。例如 http://www.dreamdu.com/xhtml/ 返回/xhtml/ location.port – 返回URL中的端口部分。例如 http://www.dreamdu.com:8080/xhtml/ 返回8080 location.protocol – 返回URL中的协议部分。例如 http://www.dreamdu.com:8080/xhtml/ 返回(//)前面的内容http: location.assign – 设置当前文档的URL location.replace() – 设置当前文档的URL,并且在history对象的地址列表中移除这个URL location.replace(url); location.reload() – 重载当前页面
(2)history对象
History 对象是 window 对象的一部分,可通过 window.history 属性对其进行访问
history.go() – 前进或后退指定的页面数或指定的url, history.go(num/url); history.back() – 后退一页 history.forward() – 前进一页
(3)Navigator对象
navigator.userAgent – 返回用户代理头的字符串表示(就是包括浏览器版本信息等的字符串) 跨域用于查看当前所处的环境。
let sUserAgent = navigator.userAgent.toLowerCase()
let bIsIpad = sUserAgent.match(/ipad/i) == 'ipad'
let bIsIphoneOs = sUserAgent.match(/iphone os/i) == 'iphone os'
let bIsMidp = sUserAgent.match(/midp/i) == 'midp'
let bIsUc7 = sUserAgent.match(/rv:1.2.3.4/i) == 'rv:1.2.3.4'
let bIsUc = sUserAgent.match(/ucweb/i) == 'ucweb'
let bIsAndroid = sUserAgent.match(/android/i) == 'android'
let bIsCE = sUserAgent.match(/windows ce/i) == 'windows ce'
let bIsWM = sUserAgent.match(/windows mobile/i) == 'windows mobile'
if (
!(
bIsIpad ||
bIsIphoneOs ||
bIsMidp ||
bIsUc7 ||
bIsUc ||
bIsAndroid ||
bIsCE ||
bIsWM
)
) {
alert('pc端')
} else {
alert('移动端')
}
navigator.cookieEnabled – 返回浏览器是否支持(启用)cookie
拖放(Drag 和 Drop)是很常见的特性。它指的是您抓取某物并拖入不同的位置。
拖放是 HTML5 标准的组成部分:任何元素都是可拖放的。
dragstart:事件主体是被拖放元素,在开始拖放被拖放元素时触发。
darg:事件主体是被拖放元素,在正在拖放被拖放元素时触发。
dragenter:事件主体是目标元素,在被拖放元素进入某元素时触发。
dragover:事件主体是目标元素,在被拖放在某元素内移动时触发。
dragleave:事件主体是目标元素,在被拖放元素移出目标元素是触发。
drop:事件主体是目标元素,在目标元素完全接受被拖放元素时触发。
dragend:事件主体是被拖放元素,在整个拖放操作结束时触发
首先补充一下,http和https的区别,相比于http,https是基于ssl加密的http协议
简要概括:http2.0是基于1999年发布的http1.0之后的首次更新。
提升访问速度(可以对于,请求资源所需时间更少,访问速度更快,相比http1.0)
允许多路复用:多路复用允许同时通过单一的HTTP/2连接发送多重请求-响应信息。改善了:在http1.1中,浏览器客户端在同一时间,针对同一域名下的请求有一定数量限制(连接数量),超过限制会被阻塞。
二进制分帧:HTTP2.0会将所有的传输信息分割为更小的信息或者帧,并对他们进行二进制编码
首部压缩
服务器端推送
(1)400状态码:请求无效
产生原因:
前端提交数据的字段名称和字段类型与后台的实体没有保持一致
前端提交到后台的数据应该是json字符串类型,但是前端没有将对象JSON.stringify转化成字符串。
解决方法:
对照字段的名称,保持一致性
将obj对象通过JSON.stringify实现序列化
(2)401状态码:当前请求需要用户验证
(3)403状态码:服务器已经得到请求,但是拒绝执行
fetch发送post请求的时候,总是发送2次,第一次状态码是204,第二次才成功?
原因很简单,因为你用fetch的post请求的时候,导致fetch 第一次发送了一个Options请求,询问服务器是否支持修改的请求头,如果服务器支持,则在第二次中发送真正的请求。
共同点:都是保存在浏览器端,并且是同源的
Cookie:cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。而sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下,存储的大小很小只有4KB左右。 (key:可以在浏览器和服务器端来回传递,存储容量小,只有大约4KB左右)
而localStorage始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
sessionStorage:仅在当前浏览器页面生效,如果复制域名到另一个页面则之前的sessionStorage会重置。自然也就不可能持久保持。
localStorage和sessionStorage都是在当前域名下生效,在不同域名下并不存在当前域名下的缓存。且刷新页面,不会更新之前已存的storage缓存(除非在进入页面一开始就设置storage了,这样就会修改)。
localStorage:localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的。(key:同源窗口都会共享,并且不会失效,不管窗口或者浏览器关闭与否都会始终生效)。
localStorage和SessionStorage的使用场景: localStorage常用于一些保存一些长期保存在本地的数据,比如购物车数据、网站背景等等;而sessionStorage适合于用户私密性一次性登录。
补充说明一下cookie的作用:
保存用户登录状态。例如将用户id存储于一个cookie内,这样当用户下次访问该页面时就不需要重新登录了,现在很多论坛和社区都提供这样的功能。 cookie还可以设置过期时间,当超过时间期限后,cookie就会自动消失。因此,系统往往可以提示用户保持登录状态的时间:常见选项有一个月、三个 月、一年等。
JavaScript语言采用的是单线程模型(同一时间只能做一件事),也就是说,所有任务只能在一个线程上完成,一次只能做一件事。
web worker 对象的出现 ,就是为了javascript创造多线程环境(同一时间能做多件事),语序主线程创建worker线程,将一些任务分配给后者运行。在主线程运行的同时,worker线程(外部的j其他s文件)在后台运行,两者互不干扰。生成一个专用worker
创建一个新的worker很简单。你需要做的是调用Worker()
的构造器,指定一个脚本的URI来执行worker线程(main.js):
var myWorker = new Worker('worker.js');
专用worker中消息的接收和发送
你可以通过postMessage()
方法(用于想worker线程发送数据)和onmessage
()用于接收传递过来的数据事件处理函数触发workers的方法。当你想要向一个worker发送消息时,你只需要这样做(main.js):
first.onchange = function() {
myWorker.postMessage([first.value,second.value]);
console.log('Message posted to worker');
}
second.onchange = function() {
myWorker.postMessage([first.value,second.value]);
console.log('Message posted to worker');
}
在worker中接收到消息后,我们可以写这样一个事件处理函数代码作为响应(worker.js):
onmessage = function(e) {
console.log('Message received from main script');
var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
console.log('Posting message back to main script');
postMessage(workerResult);
}
onmessage处理函数允许我们在任何时刻,一旦接收到消息就可以执行一些代码,代码中消息本身作为事件的data属性进行使用。这里我们简单的对这2个数字作乘法处理并再次使用postMessage()方法,将结果回传给主线程。
如果你需要从主线程中立刻终止一个运行中的worker,可以调用worker的terminate
方法:
myWorker.terminate();
HTML5语义化标签是指正确的标签包含了正确的内容,结构良好,便于阅读,比如nav表示导航条,类似的还有article、header、footer等等标签。
定义:iframe 元素会创建包含另外一个文档的内联框架(即行内框架),也就是可以用src=“”元素引入其他页面在一个框内显示
提示:可以将提示文字放在之间,来提示某些不支持iframe的浏览器
缺点:
会阻塞主页面的onload事件
搜索引擎无法解读这种页面,不利于SEO(网站优化)
iframe和主页面共享连接池,而浏览器对相同区域有限制所以会影响性能。
DOCTYPE是document type (文档类型) 的缩写。声明位于文档的最前面,处于标签之前,它不是html标签。主要作用是告诉浏览器的解析器使用哪种HTML规范或者XHTML规范来解析页面。
不存在或者形式不正确会导致HTML或XHTML文档以混杂模式呈现,就是把如何渲染html页面的权利交给了浏览器,有多少种浏览器就有多少种展示方式。因此要提高浏览器兼容性就必须重视
Doctype声明于文档最前面,告诉浏览器以何种方式来渲染页面,这里有两种模式,严格模式和混杂模式。
严格模式: 又称标准模式,是指浏览器按照W3C标准来解析代码,呈现页面
混杂模式: 又称为怪异模式或者兼容模式,是指浏览器按照自己的方式来解析代码,使用一种比较宽松的向后兼容的方式来显示页面。
w3c是万维网联盟,是一个致力于改善网络的组织,其中w3c是www的基本标准,并且对web进行标准化,从而来促进web之间的合作。
w3c最主要的工作就是对网络规范的规定,并且这些规范对通信协议进行了详细的描述,其中就包括对HTML5做出了详细的规范,目前HTML5的规范已经完成了,但是并不能算w3c的标准,html5是有完整的编程环境和跨平台性,同时为了减少浏览器的碎片,目前w3c开始对互操作性进行标准化。
在w3c中,网页是有三部分组成,包括结构,表现和行为。
XSS(跨站脚本攻击)是指攻击者在返回的HTML中嵌入javascript脚本,为了减轻这些攻击,需要在HTTP头部配上,
set-cookie:http-only这个属性可以防止XSS,它会禁止javascript脚本来访问cookie。
secure 这个属性告诉浏览器仅在请求为https的时候发送cookie。
//设置cookie
response.addHeader("Set-Cookie", "uid=112; Path=/; HttpOnly");
//设置多个cookie
response.addHeader("Set-Cookie", "uid=112; Path=/; HttpOnly");
response.addHeader("Set-Cookie", "timeout=30; Path=/test; HttpOnly");
//设置https的cookie
response.addHeader("Set-Cookie", "uid=112; Path=/; Secure; HttpOnly");
当客户端第一次向服务器端发送请求时,服务器端会创建一个session,同时会生成该session对应的sessionId,并传回客户端,以后当客户端再次发送请求时,都会带上这个sessionId,这样服务器端就知道此客户进程的状态了。其实在前端,sessionId可存放在cookie中,可通过document.cookie来设置cookie。
cookie和session都是用来跟踪浏览器用户身份的会话方式
Cookie和session都可用来存储用户信息,cookie存放于客户端,session存放于服务器端,因为cookie存放于客户端有可能被窃取,所以cookie一般用来存放不敏感的信息,比如用户设置的网站主题,敏感的信息用session存储,比如用户的登陆信息,session可以存放于文件,数据库,内存中都可以,cookie可以服务器端响应的时候设置,也可以客户端通过JS设置cookie会在请求时在http首部发送给客户端,cookie一般在客户端有大小限制,一般为4K。
简单来说就是当用户第一次项服务器端发送请求时,会在服务器端创建一个session对象,通过req.session.userName = "ww"创建,然后会将此session回传给客户端,然后客户端拿到以后会进行保存,之后每次发送异步请求时都会携带此session,这样就能够判断是否此用户是否是登录状态。
//导入express-session模块
const session = require('express-session');
//先配置session,实现session功能
app.use(session({
secret: 'keyboard cat', //加密的字符串,里面内容可以随便写
resave: false, //强制保存session,即使它没变化
saveUninitialized: false //强制将未初始化的session存储,默认为true
}));
//然后当客户端向服务器端请求时,触发某个后端写的接口,在这里这个接口里面设定session内容
async (req, res) => {
//接收请求参数
// console.log(req.body);
const { email, password } = req.body; //进行解构
if (email.trim().length == 0 || password.trim().length == 0) return res.status(400).render('admin/error.art', { msg: '邮件地址或密码错误' }); //一般服务器端参数格式错误,则返回状态码400
//根据邮箱地址查询用户信息
let user = await User.findOne({ email: email });
// 若查询到用户则是一个对象形式,里面含有此用户的各种信息,如果没查询到则是一个空对象
if (user) {
//将客户端传递过来的密码和用户信息中的密码进行比对,compare()方法返回的是一个bollean值,若比对成功则返回true,否则比对失败
//第一个参数是浏览器传过来的密码,第二个参数是数据库中用户的密码
let isValid = await bcrypt.compare(password, user.password);
if (isValid) {
//密码比对正确,登陆成功
//将用户名存储到请求对象中
//在服务器端向session当中存入数据,服务器端将为session对象设定一个特定的sessionID,并存到服务器端
req.session.username = user.username;//设置session
//不用模板渲染的方法,可以用express模块提供的重定向方法redirect()
res.status(200).render('admin/user', {
msg: req.session.username
});
//若密码比对成功则进行重定向重新跳转页面
//req.app.locals.userInfo = user;
//res.redirect('/admin/user');
} else {
//密码错误登录失败
res.status(400).render('admin/error', { msg: '密码错误' });
}
} else {
//没有查询到用户
res.status(400).render('admin/error', { msg: '邮箱地址或密码错误' });
}
}
const guard = (req, res, next) => {
//判断用户访问的是否是登录页面
//如果用户是登陆的,则请求放行,
//若用户不是登陆的。则将请求重定向到登录页面
if (req.url != '/login' && !req.session.username) {
res.redirect('/admin/login');
} else {
//用户是登录状态,请求放行
next();
}
}
//客户端js设置cookie
document.cookie = "name="+userName;
//服务器端设置cookie
var http = require('http');
var fs = require('fs');
http.createServer(function(req, res) {
res.setHeader('status', '200 OK');
res.setHeader('Set-Cookie', 'isVisit=true;domain=.yourdomain.com;path=/;max-age=1000');
res.write('Hello World');
res.end();
}).listen(8888);
console.log('running localhost:8888')
//浏览器端拿到cookie
document.cookie
HTTP是一种无状态的协议,为了分辨链接是谁发起的,需自己去解决这个问题。不然有些情况下即使是同一个网站每打开一个页面也都要登录一下。而Session和Cookie就是为解决这个问题而提出来的两个机制。
1、cookie 和session的区别是:cookie数据保存在客户端,session数据保存在服务器端。
2、两个都可以用来存私密的东西,同样也都有有效期的说法,区别在于session是放在服务器上的,过期与否取决于服务期的设定,cookie是存在客户端的,过去与否可以在cookie生成的时候设置进去。
(Representational State Transfer)Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
简要介绍:前端开发中,静态网页通常需要适应不同分辨率的设备,常用的自适应解决方案包括媒体查询、百分比、rem和vw/vh等
像素是网页布局的基础,一个像素表示了计算机屏幕所能显示的最小区域,像素分为两种类型:css像素和物理像素。
广义的视口,是指浏览器显示内容的屏幕区域,狭义的视口包括了布局视口、视觉视口和理想视口。
rem指的是元素大小以html根元素的字体大小来成倍增大的,而em是根据自己上一层父元素的字体大小来改变自己的大小
在前面我们说到,不同端的设备下,在css文件中,1px所表示的物理像素的大小是不同的,因此通过一套样式,是无法实现各端的自适应。由此我们联想:
使用@media媒体查询可以针对不同的媒体类型定义不同的样式,特别是响应式页面,可以针对不同屏幕的大小,编写多套样式,从而达到自适应的效果。举例来说:
@media screen and (max-width: 960px){
html{
background-color:#FF6699
font-size:100px; //设置html的字体大小,之后在html中的一些标签中就可以使用rem为单位根据html文字大小动态调整自己的长度或者宽度大小了。
}
}
span {
width: 2rem; //这里等价于width长为200px
}
@media screen and (max-width: 768px){
body{
background-color:#00FF66;
}
}
@media screen and (max-width: 550px){
body{
background-color:#6633FF;
}
}
@media screen and (max-width: 320px){
body{
background-color:#FFFF00;
}
}
但是媒体查询的缺点也很明显,如果在浏览器大小改变时,需要改变的样式太多,那么多套样式代码会很繁琐。
也就是调用bootstrap框架里面自带的类(比如.container)就能够实现自适应
其中单独制作移动端页面一般采用前三种,但最多的是使用flex和rem混合布局;
响应式布局可以使用媒体查询和rem搭配,或者直接使用Bootstrap框架进行配置页面。
原因:因为有得时候是因为双击屏幕产生缩放,当用户点击屏幕后,手机会等待300ms左右判断用户是否还会点击进行页面放大,如果没有就是普通的点击事件,否则就是方法操作。
(1)粗暴型,禁用缩放 user-scalable=“no”
user-scalable=no表明这个页面不可缩放,也就是浏览器禁用的双击缩放事件并且同时会去掉300ms点击延迟。 但这个方案也有缺点,就是完全禁用了双击缩放,当我们需要放大文字或者图片时无法满足我们的需求。
(2)利用FastClick,其原理是:
FastClick 是 FT Labs 专门为解决移动端浏览器 300 毫秒点击延迟问题所开发的一个轻量级的库。FastClick的实现原理是在检测到touchend事件的时候,会通过DOM自定义事件立即触发模拟一个click事件,并把浏览器在300ms之后的click事件阻止掉。
使用fastclick需要先引入fastclick模块,npm install fastclick,然后在js文件中引入后再写js代码如下:
js版本
if ('addEventListener' in document) {
document.addEventListener('DOMContentLoaded', function() {
FastClick.attach(document.body);
}, false);
}
jQuery版本
$(function() {
FastClick.attach(document.body);
});
Common JS模块的系统方式
var attachFastClick = require('fastclick');
attachFastClick(document.body);
注意:在移动端触摸屏幕事件是touchStart touchmove、touchend
在pc端是鼠标事件:mousedown、mouseup
addEventListener(event, function, useCapture)
其中,event指定事件名;function指定要事件触发时执行的函数;useCapture指定事件是否在捕获或冒泡阶段执行。
若useCapture为true,则会在捕获阶段时触发执行函数,子父元素都有click事件,则会先触发自己的父元素的点击事件(因为处于捕获阶段时触发执行函数)
链接:https://www.nowcoder.com/questionTerminal/98fdf5c3530e49959bd29309d17bbb3c?orderByHotValue=1&page=1&onlyReference=false 来源:牛客
iframe通信,同源和不同源两种情况 同域:即父子页面相互调用
父调用子页面用contentWindow属性
子调用父页面用parent属性
一、父页面调用子页面 1、先得到子页面的document document.getElementById(‘FrameId’).contentWindow.document
contentWindow属性用法:
2、得到子页面的window document.getElementById(‘FrameId’).contentWindow.window 重载子页面:document.getElementById(‘FrameId’).contentWindow.window.location.reload(true); 或者 $(‘#FrameId’).attr(‘src’,‘…/list’); 3、得到子页面的的变量 doucment. iframe的name属性值 . 子页面变量名称 (document.frameName.temp) 二、子页面调用父页面 1、父页面document : window.parent.document 2、获得父页面变量 : parent.变量名称 3、调用事件 : window.parent.XXX();
跨域: 主域:由两个或两个以上的字母构成,中间由点号隔开,整个域名只有1个点号 csdn.net 子域:是在主域名之下的域名,域名内容会有多个点号
未跨主域,跨子域 两个域的js文件中设置document.domain=主域名 即可
跨主域 location.hash (B操作A) 1、动态改变location.hash,iframe不会重载 2、无论跨域与否,iframe内可以获取自己的location.hash 3、只要域名相同就能通信,即使ABC三层嵌套
http状态码有哪些,这也是一个很高频的面试问题。 一般大家都知道404页面不存在,500服务器错误,301重定向,302临时重定向,200ok,401未授权、404资源未找到。
可以重点介绍三个状态码及相关的知识,他们分别是304协商缓存,101协议升级,以及307hsts跳转。
100 Continue 继续。客户端应继续其请求
101 Switching Protocols 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议
200 OK 请求成功。一般用于GET与POST请求
204:请求被受理但没有资源可以返回
206:客户端只是请求资源的一部分,服务器只对请求的部分资源执行GET方法,相应报文中通过Content-Range指定范围的资源。
301 Moved Permanently 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
302 Found 临时移动。 与301类似。但资源只是临时被移动。客户端应继续使用原有URI
301比较常用的场景是使用域名跳转。302用来做临时跳转 比如未登陆的用户访问用户中心重定向到登录页面。
304协商缓存
浏览器缓存分为强缓存和协商缓存,优先读取强缓存。
如果服务器端响应304,则是告知客户端资源直接从缓存中取就可以,
如果返回200,则是向客户端返回的是新的资源
对于强缓存而言,是浏览器优先读取的,如果不能命中强缓存,则就向服务器端发送请求,再检查是否命中协商缓存。
协商缓存也就是对于有协商缓存策略的服务器来说,当浏览器端向服务器端请求资源文件时,会一同把请求和资源标识(比如etag)发送到服务器端,服务器端会对比资源是否过期(这里是对比资源标识是否一致),如果一致这说明是资源未过期,服务器端返回304状态码标识协商缓存,意思是让客户端直接读取自己缓存中的资源就可以;如果资源过期了,则返回状态码200,并把最新资源和最新标识进行发送,客户端得到最新数据后会进行更新缓存。
305 Use Proxy 使用代理。所请求的资源必须通过代理访问
400 Bad Request 客户端请求的语法错误,服务器无法理解
401 Unauthorized 请求要求用户的身份认证
402 Payment Required 保留,将来使用
403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
405 Method Not Allowed 客户端请求中的方法被禁止
500 Internal Server Error 服务器内部错误,无法完成请求 请求报文语法有误,服务器无法识别(浏览器端没有根据服务器端的参数进行请求,可能缺少参数)
503 Service Unavailable 服务器正忙 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
设置请求头,使用: xhr.setRequestHeader();
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Content-Length', JSON.stringify(data).length);
xhr.send(JSON.stringify(data));
注意: xhr.setRequestHeader() 必须在xhr.open()之后, xhr.send()之前调用;
协议头 | 说明 |
---|---|
Accept | 可接受的响应内容类型(Content-Types)。 |
Accept-Charset | 可接受的字符集 |
Accept-Encoding | 可接受的响应内容的编码方式。 |
Accept-Language | 可接受的响应内容语言列表。 |
Accept-Datetime | 可接受的按照时间来表示的响应内容版本 |
Authorization | 用于表示HTTP协议中需要认证资源的认证信息 |
Cache-Control | 用来指定当前的请求/回复中的,是否使用缓存机制。 |
Connection | 客户端(浏览器)想要优先使用的连接类型 |
Cookie | 由之前服务器通过Set-Cookie(见下文)设置的一个HTTP协议Cookie |
Content-Length | 以8进制表示的请求体的长度 |
Content-MD5 | 请求体的内容的二进制 MD5 散列值(数字签名),以 Base64 编码的结果 |
Content-Type | 请求体的MIME类型 (用于POST和PUT请求中) |
Date | 发送该消息的日期和时间(以RFC 7231中定义的"HTTP日期"格式来发送) |
Expect | 表示客户端要求服务器做出特定的行为 |
From | 发起此请求的用户的邮件地址 |
Host | 表示服务器的域名以及服务器所监听的端口号。如果所请求的端口是对应的服务的标准端口(80),则端口号可以省略。 |
If-Match | 仅当客户端提供的实体与服务器上对应的实体相匹配时,才进行对应的操作。主要用于像 PUT 这样的方法中,仅当从用户上次更新某个资源后,该资源未被修改的情况下,才更新该资源。 |
If-Modified-Since | 允许在对应的资源未被修改的情况下返回304未修改 |
If-None-Match | 允许在对应的内容未被修改的情况下返回304未修改( 304 Not Modified ),参考 超文本传输协议 的实体标记 |
If-Range | 如果该实体未被修改过,则向返回所缺少的那一个或多个部分。否则,返回整个新的实体 |
If-Unmodified-Since | 仅当该实体自某个特定时间以来未被修改的情况下,才发送回应。 |
Max-Forwards | 限制该消息可被代理及网关转发的次数。 |
Origin | 发起一个针对跨域资源共享的请求(该请求要求服务器在响应中加入一个Access-Control-Allow-Origin的消息头,表示访问控制所允许的来源)。 |
Pragma | 与具体的实现相关,这些字段可能在请求/回应链中的任何时候产生。 |
Proxy-Authorization | 用于向代理进行认证的认证信息。 |
Range | 表示请求某个实体的一部分,字节偏移以0开始。 |
Referer | 表示浏览器所访问的前一个页面,可以认为是之前访问页面的链接将浏览器带到了当前页面。Referer其实是Referrer这个单词,但RFC制作标准时给拼错了,后来也就将错就错使用Referer了。 |
TE | 浏览器预期接受的传输时的编码方式:可使用回应协议头Transfer-Encoding中的值(还可以使用"trailers"表示数据传输时的分块方式)用来表示浏览器希望在最后一个大小为0的块之后还接收到一些额外的字段。 |
User-Agent | 浏览器的身份标识字符串 |
Upgrade | 要求服务器升级到一个高版本协议。 |
Via | 告诉服务器,这个请求是由哪些代理发出的。 |
Warning | 一个一般性的警告,表示在实体内容体中可能存在错误。 |
如果跨域请求资源,就会遇到Cross-Origin Resource Sharing(CORS)跨域资源共享问题
跨域,简要来说就是一个服务器上的文件,要访问另一个服务器上的文件是不被允许的是跨域的。
浏览器在发送跨域请求的时候,会有哪些过程
如果是简单请求,浏览器会先发送请求,然后判断服务器返的返回头中是否支持跨域请求,否则就会抛出跨域异常;
如果是非简单请求,浏览器会先发出OPTIONS请求方法的检测命令,判断服务器是否支持跨域请求,如果支持则发送真正的请求,如果不支持则抛出跨域异常,因此一个非简单请求每次会发送两个请求,后面跨域解决方案会讲到缓存OPTIONS预检请求
跨域解决方案
方案1: 禁用浏览器跨域校验,即允许跨域访问,(这种方案不可取,不可能让所有的浏览器设置允许跨域访问,浏览器添加属性–disable-web-security)
方案2: 动态创建script标签来实现跨域请求,
jsonp的缺点:http请求只支持get方法;jsonp在调用失败的时候不会返回各种HTTP状态码
jsonp则是动态添加
前端:
<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
跨域测试
");
});
});
后端:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
//数据
List studentList = getStudentList();
JSONArray jsonArray = JSONArray.fromObject(studentList);
String result = jsonArray.toString();
//前端传过来的回调函数名称
String callback = request.getParameter("callback");
//用回调函数名称包裹返回数据,这样,返回数据就作为回调函数的参数传回去了
result = callback + "(" + result + ")";
response.getWriter().write(result);
}
方案3 使用jquery的jsonp方式跨域请求
jsonp是一种跨域请求方式。主要原理是利用了script标签可以跨域请求的特点,由其src属性发送请求到服务器,服务器返回js代码,网页端接受响应,然后就直接执行了,这和通过script标签引用外部文件的原理是一样的。
json是一种数据交换的格式。
jsonp的实现方式其实就是
服务端代码不变,js代码如下:最简单的方式,只需配置ajax请求的dataType:‘jsonp’,就可以发起一个跨域请求。jsonp指定服务器返回的数据类型为jsonp格式,jsonp是不支持POST方式的,就算指定成POST方式,会自动转为GET方式;
这里的success就跟上面的showData一样,如果有success函数则默认success()作为回调函数
<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
跨域测试
方案4 服务端解决跨域问题
通过在response对象中添加响应头,告诉浏览器允许跨域访问,* 号代表允许所有的请求域名,所有的请求方法跨域访问
前端在发送请求前需添加请求头告知服务器端需要使用origin
const app = express()
app.use(...)
app.setRequestHeader("origin","...");
后端返回数据前需添加响应头:
res.addHeader("Access-Control-Allow-Origin", *);
方案5 使用代理
前端proxy代理搭配nginx配置代理之后实现可跨域。
前端配置代理:
export default defineConfig({
// ...
server: {
//...
proxy: {
'/api': {
target: 'http://www.baidu.com', // 真正请求的url
changeOrigin: true,
rewrite: (path) => path.replace(/^/api/, '')
},
}
}
})
nginx配置代理:只修改conf->nginx.conf 里面的配置
server {
listen 80;
server_name localhost;
location /api/ { // 千万别漏掉斜杠哦
proxy_pass http://www.baidu.com/;
}
}
304为协商缓存
浏览器缓存分为强缓存和协商缓存,优先读取强制缓存。:
服务端先判断所相应资源是否已经修改过,如果没有修改,则服务器端响应304,则是告知客户端资源直接从缓存中取就可以。
如果资源修改了,则返回200,且服务器同时向客户端返回的是新的修改后的资源
在js中,call和apply都是为了改变某个函数内部的this指向的。除了他们,还有bind()方法
我们可以通过改变this指向来调用其他对象的方法,而不用自己构造一些方法。
call和apply都属于Function.prototype的一个方法,所以每一个构造对象Function的实例对象都会有call和apply方法,这两个方法的作用是相同的(都是为了改变this指向),只是使用方式不同而已。
区别:传递的参数不同,bind()是重新创建一个函数,而不会立即执行
call接受的从第二个参数起是一个参数列表,而apply接受的是一个参数数组。对于bind()函数,他会改变this指向,并且会重新创建一个函数,当想要调用的时候就可以调用了()这些参数(如果有的话)作为 bind() 的第二个参数跟在 this 后面,之后它们会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们的后面。也可以不传,不传参的话就是使用的是默认列表。
dog、cat是个对象
dog.func.call(cat,arg1,arg2), //参数要按顺序传递,当你的参数是明确知道数量时用call,而不确定时用apply
dog.func.apply(cat,[arg1,arg2])
dog.func.bind(cat,arg1)
对于bind()
function fn(a, b, c) {
return a + b + c;
}
var _fn = fn.bind(null, 10);
var ans = _fn(20, 30, 40); // 60
减少资源的网络请求,比如css样式,可将多个css样式文件合并并压缩为一个css文件。
使用DNS缓存、304协商缓存、使用CDN。
减少重排重绘
在写代码时可以多采用按需加载,路由懒加载、图片懒加载等等…
减短首屏加载时间:
a. 使用骨架屏:在数据未加载完时,使用静态的骨架样式进行展示。
b. 使用动态Polyfill
c. 使用资源预加载
//在上一个组件中提前加载下一个组件,并使用react.lazy()进行懒加载,不会阻塞当前组件的渲染。
const stockChartPromise = import("./StockChart");
const StockChart = React.lazy(() => stockChartPromise);
* 删除不必要的代码和注释包括空格,尽量做到最小化文件。
* 可以利用 GZIP 压缩文件。
* 结合 HTTP 缓存文件。
利用图片懒加载技术
首先,DOM 和 CSSOM 通常是并行构建的,所以 CSS 加载不会阻塞 DOM 的解析。
然而,由于 Render Tree 是依赖于 DOM Tree 和 CSSOM Tree 的, 所以他必须等待到 CSSOM Tree 构建完成,也就是 CSS 资源加载完成(或者 CSS 资源加载失败)后,才能开始渲染。因此,CSS 加载会阻塞 Dom 的渲染。
由此可见,对于 CSSOM 缩小、压缩以及缓存同样重要,我们可以从这方面考虑去优化。
* 减少关键 CSS 元素数量
* 当我们声明样式表时,请密切关注媒体查询的类型,它们极大地影响了 CRP 的性能 。
当浏览器遇到 script 标记时,GUI线程会停止构建render树,紧接着js引擎线程会开始解析执行script脚本,当script脚本执行完后才会将控制权交由GUI线程继续构建render树。
写算法时尽量时间复杂度低一些
*async: 当我们在 script 标记添加 async 属性以后,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。
* defer: 与 async 的区别在于,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded事件触发之前完成。
* 预加载 —— preload & prefetch 。
* DNS 预解析 —— dns-prefetch 。
防抖(debounce)/节流(throttle)
即在第一次触发事件时,不立即执行函数,而是给出一个期限值(这里使用定时器实现)等定时器结束后再执行想要的操作,然后
输入搜索时,可以用防抖debounce等优化方式,减少http请求; //原理是当输入框监听到输入时都会先清除定时器,然后重新创建并触发定时器,当计时器结束时才会发起http请求
这里以输入框进行自动搜索时,进行防抖操作
function debounce(fn,time) {
let timeout = null; // 创建一个标记用来存放定时器的返回值
return function () {
if (timeout) {
clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉
}
timeout = setTimeout(() => { // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数
fn().call(this);//arguments是传入的参数
}, time);
};
}
function sayHi() {
console.log('防抖成功');
}
var inp = document.getElementById('inp');
inp.addEventListener('input', debounce(sayHi,5000)); // 防抖
有参数的情况:
//假设我要传两个参数,既然fn里传不了那就在debounce里传
element.onclick = debounce (fn, delay, 1, 2);
//简单的举个fn的例子
function fn (e, num1, num2) {
console.log(e, num1, num2);
}
function debounce (fn, delay, ...nums) {
let temp = null;
return function (e) {
if(temp) clearTimeout(temp);
temp = setTimeout(() => {
//e是事件处理函数都有的一个参数,nums是个数组,在用call的时候需要解构一下
fn.call(this, e, ...nums)
//当然这里也可以用apply但是要麻烦很多因为nums是数组,但还有个e
}, delay);
}
}
或者这样:
element.onclick = debounce(fn, delay).bind(element,'value1','value2');
function debounce (fn, delay) {
let temp = null;
return function () {
//因为这个函数是事件处理函数所以这个函数中的this就是element
if(temp) clearTimeout(temp);
temp = setTimeout(() => {
fn.call(this,...arguments); //你也可以用apply
}, delay);
}
}
节流函数:只允许一个函数在N秒内执行一次(控制高频时间执行次数)。
如果短时间内大量触发同一事件,那么在函数执行一次之后,该函数在指定的时间期限内不再工作,直至过了这段时间才重新生效。
实现 这里借助setTimeout
来做一个简单的实现,加上一个状态位valid
来表示当前函数是否处于工作状态:
let valid = true
return function() {
if(!valid){
//休息时间 暂不接客
return false
}
// 工作时间,执行函数并且在间隔期内把状态位设为无效
valid = false
setTimeout(() => {
fn()
valid = true;
}, delay)
}
}
/* 请注意,节流函数并不止上面这种实现方案,
例如可以完全不借助setTimeout,可以把状态位换成时间戳,然后利用时间戳差值是否大于指定间隔时间来做判定。
也可以直接将setTimeout的返回的标记当做判断条件-判断当前定时器是否存在,如果存在表示还在冷却,并且在执行fn之后消除定时器表示激活,原理都一样
*/
// 以下照旧
function showTop () {
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
}
window.onscroll = throttle(showTop,1000)
使用场景:单纯获取资源的请求就规定为 GET、修改服务器资源的请求或者获取一些私密性的数据执行一些安全性的操作比如登录就规定为 POST。
GET和POST是HTTP请求的两种基本方法;
GET在浏览器回退时是无害的,而POST会再次提交请求。( 这句话简单理解就是,get会将请求参数放在请求的url中,回退操作实际上浏览器会从之前的缓存中拿结果;post每次调用都会创建新的资源。
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留
GET请求在URL中传送的参数是有长度限制的,而POST没有。
对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
GET请求只能进行url编码(get请求的参数只能是ascll,不是的话就需要进行url编码转化为ascll),而POST支持多种编码方式(UTF-8)。
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
最直观的区别是GET参数通过URL传递,POST放在Request body中。
GET产生一个TCP数据包;POST产生两个TCP数据包。
对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);
而对于POST,浏览器先发送header, 包含一个Expect:100-continue, 询问Server使用愿意接受数据,浏览器再发送data,服务器响应200 ok(返回数据)。
GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE, CONNECT
三角形原理:边框的均分原理,会均分矩形的直角
div {
width: 0;
height: 0;
border: 10px solid blue;
border-top-color: pink;
}
盒子模型有两种,content-box、border-box
box-sizing
属性被指定为下面列表中的关键字。
content-box
默认值,标准盒子模型。 width
与 height
只包括内容的宽和高, 不包括边框(border),内边距(padding),外边距(margin)。注意: 内边距、边框和外边距都在这个盒子的外部。 比如说,.box {width: 350px; border: 10px solid black;}
在浏览器中的渲染的实际宽度将是 370px。 尺寸计算公式:
width
= 内容的宽度
height
= 内容的高度
宽度和高度的计算值都不包含内容的边框(border)和内边距(padding)。
border-box
width
和 height
属性包括内容,内边距和边框,但不包括外边距。也称为IE盒模型。注意,填充和边框将在盒子内 , 例如, .box {width: 350px; border: 10px solid black;}
导致在浏览器中呈现的宽度为350px的盒子。内容框不能为负,并且被分配到0,使得不可能使用border-box使元素消失。 尺寸计算公式:
width
= border + padding + 内容的宽度
height
= border + padding + 内容的高度
标准盒子模型:
IE盒子模型:
缓存分为两种:强缓存和协商缓存,根据响应头的http状态码来决定。
对于强缓存而言,是浏览器优先读取的,如果不能命中强缓存,则就向服务器端发送请求,再检查是否命中协商缓存。
协商缓存也就是对于有协商缓存策略的服务器来说,当浏览器端向服务器端请求资源文件时,会一同把请求和资源标识(比如etag)发送到服务器端,服务器端会对比资源是否过期(这里是对比资源标识是否一致),如果一致这说明是资源未过期,服务器端返回304状态码标识协商缓存,意思是让客户端直接读取自己缓存中的资源就可以;如果资源过期了,则返回状态码200,并把最新资源和最新标识进行发送,客户端得到最新数据后会进行更新缓存。
强缓存相关字段有expires(过期),cache-control。如果cache-control与expires同时存在的话,cache-control的优先级高于expires。
缓存相关字段有Last-Modified/If-Modified-Since,Etag/If-None-Match
强缓存是利用 Expires 和 Cache-Control 这2个字段来控制的,控制资源缓存的时间,在有效期内不会去向服务器请求了。
Expires: Wed, 25 Jul 2028 19:19:42 GMT
表示资源会在2028-07-25 19:19:42后过期,到时候需要再次请求资源了。由于 Expires 是依赖于客户端系统时间,当修改了本地时间后,缓存可能会失效,所以一般情况,我们认为使用 Cache-Control 是更好的选择。
Date ~ Date +259200s
这段时间里都是有效的。Cache-control: max-age=259200
表示资源3天后过期,需要向服务器再次请求资源了。
Cache-Control 与 Expires 可以在服务端配置同时启用,也就是说在 response header 中,Expires 和Cache-Control 是可以同时存在,当它们同时启用的时候Cache-Control 优先级更高。
协商缓存是由服务器来确定缓存资源是否可用,当然了,需要服务器和客户端一起配合。服务器可在 response header 中包含Last-Modified字段或者ETag字段。
首先html5为了更好的实践web语义化,增加了header,footer,nav,aside,section等语义化标签,
在表单方面,为了增强表单,为input增加了color,emial,data ,range等类型,
在存储方面,提供了sessionStorage,localStorage,和离线存储,通过这些存储方式方便数据在客户端的存储和获取,
在多媒体方面规定了音频和视频元素audio和vedio,
另外还有地理定位,canvas画布,拖放duag,多线程编程的web worker和websocket协议
html4新增了history.pushState和replaceState路由跳转
CSS3边框如border-radius,box-shadow等;CSS3背景如background-size,background-origin等;CSS3 2D,3D转换如transform等;CSS3动画如animation等。 参考https://www.cnblogs.com/xkweb/p/5862612.html
这是一个必考的面试问题,
大致上是这样一个过程:
DNS解析
TCP连接
发送HTTP请求
服务器处理请求并返回HTTP报文
浏览器解析渲染页面
tcp断开连接
第一种答法(自己总结): 当输入一个url后,首先客户端会通过域名解析DNS协议向域名服务器解析这个域名对应的ip地址,当得到ip地址后,浏览器端会跟客户端通过三次握手建立一个TCP连接。当TCP连接建立完成之后,浏览器端会在这个可靠连接的基础上发送一个http请求报文(报文会经过应用层、传输层、网络层、数据链路层、物理层进行封装头部和尾部发送到服务器端,到达服务器端后,服务器端会对其进行拆头拆尾,直到到达服务器端的应用层对这个报文进行解析并进行相应),此时服务器端会对其进行响应资源。当客户端收到之后,就会把这个页面渲染到浏览器上(渲染过程中一些js文件会阻塞页面的渲染,所以js脚本一般都放到HTML代码的后面;之后再会处理css文件。而且在渲染过程中需要考虑缓存问题,如果缓存中有满足强缓存的数据,则不会向服务器端发送请求,而是优先读取强缓存中的数据,如果不满足强缓存,那么再向服务器端发送请求,判断是否满足协商缓存,满足则返回304则读取浏览器缓存中的数据,如果不满足则返回200,并返回最新的数据以及最新的标识)。
第二种答法(网上做法) :输入url后,首先需要找到这个url域名的服务器ip,为了寻找这个ip,浏览器首先会寻找缓存,查看缓存中是否有记录,缓存的查找记录为:浏览器缓存-》系统缓存-》路由器缓存,缓存中没有则查找系统的hosts文件中是否有记录,如果没有则查询DNS服务器,得到服务器的ip地址后,浏览器根据这个ip以及相应的端口号,构