HTTPS和HTTP的主要区别
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
HTTP请求报文
-
请求行:包括请求方法、请求的url、http协议及版本。
-
请求头:一大堆的键值对。
-
空行指的是:当服务器在解析请求头的时候,如果遇到了空行,则表明,后面的内容是请求体。
-
请求体:数据部分。
HTTP响应报文
-
状态行:http协议及版本、状态码及状态描述。
-
响应头
-
空行
-
响应体
HTTP的header有哪些
request header:Accept-Encoding,Accept-Language,Connection,Host,Origin,Referer,User-Agent
response header:Content-Encoding,Content-Length,Content-Type,Server,Cookie,Set-Cookie
HTTP长连接和WebSocket长连接
从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:
Connection:keep-alive
- Keep-alive的确可以实现长连接,但是这个长连接是有问题的,本质上依然是客户端主动发起-服务端应答的模式,是没法做到服务端主动发送通知给客户端的。也就是说,在一个HTTP连接中,可以发送多个Request,接收多个Response。但是请记住Request = Response , 在HTTP中永远是这样,一个request只能有一个response。而且这个response也是被动的,不能主动发起。但是websocket就不同,websocket是可以互相主动发起的。
- Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接需要客户端和服务端都支持长连接。
HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。
一次完整的HTTP请求过程
1.对www.baidu.com这个网址进行DNS域名解析,得到对应的IP地址
2.根据这个IP,找到对应的服务器,发起TCP的三次握手
3.建立TCP连接后发起HTTP请求
4.服务器响应HTTP请求,浏览器得到html代码
5.浏览器解析html代码,并请求html代码中的资源(如js、css图片等)(先得到html代码,才能去找这些资源)
6.浏览器对页面进行渲染呈现给用户
7.断开TCP连接
TCP三次握手的原因
- ACK确保双方都可以正常接收信息
TCP四次挥手的原因
- CLOSE-WAIT:确保服务器发送完剩下的信息
- TIME-WAIT:确保浏览器最后一个ACK能够到达服务器
Get 和 Post的区别
Http状态码分类
继承的几种方式
继承的本质就是原型链
1. 借助构造函数 function Child() { Parent.call(this) }
缺点:Child 无法继承 Parent 的原型
2. 通过原型链实现继承 Child.prototype = new Parent()
缺点:如果修改 child1实例的name属性,child2实例中的name属性也会跟着改变。
3. 组合的方式:构造函数 + 原型链
缺点:让父亲Parent的构造方法执行了两次
4. 使用ES6的extends方式
前后端如何通信
主要有以下几种方式:
-
Ajax:不支持跨域。
-
WebSocket:不受同源策略的限制,支持跨域。
-
CORS:不受同源策略的限制,支持跨域。一种新的通信协议标准。可以理解成是:同时支持同源和跨域的Ajax。
跨域通信的几种方式
-
1、JSONP
-
2、WebSocket
-
3、CORS
-
4、Hash
-
5、postMessage
CSRF攻击防御
- Token验证
- Referer验证
XSS攻击防御
- 对输入过滤
- 对输出编码
浏览器渲染机制,Reflow,Repaint,Layout
JavaScript的运行机制
只要主线程空了(同步任务),就会去读取"任务队列"(异步任务),这就是JavaScript的运行机制。
提升页面性能优化的方法有哪些
-
1、资源压缩合并,减少http请求
-
2、非核心代码异步加载(动态脚本加载,defer,async)
- 3、利用浏览器缓存
(强缓存:Expires、Cache-Control 协商缓存:Last-Modified
、If-Modified-Since和
ETag
、If-None-Match
)
缓存是所有性能优化的方式中最重要的一步,这个一定要答好。【重要】
有的人可能会回答local storage 和session storage,其实不是这个。浏览器缓存和存储不是一回事。
- 4、使用CDN
浏览器第一次打开页面时,缓存是起不了作用的。CDN这一条,一定要说出来。
- 5、DNS预解析
<meta http-equiv="x-dns-prefetch-control" content="on"> 强制打开超链接的DNS预解析 <link rel="dns-prefetch" href="http://www.smyhvae.com/"> 打开该URL请求资源的预解析
前端错误监控
即时运行错误(代码错误)
方式1:try ... catch。
方式2:window.onerror
函数。这个函数是全局的。
window.onerror = function(msg, url, row, col, error) { ... }
资源加载错误
方式1:object.onerror。img标签、script标签等节点都可以添加onerror事件,用来捕获资源加载的错误。
方式2:performance.getEntries。可以获取所有已加载资源的加载时长,通过这种方式,可以间接的拿到没有加载的资源错误。
方式3:Error事件捕获。源加载错误,虽然会阻止冒泡,但是不会阻止捕获。
错误上报的两种方式
方式一:采用Ajax通信的方式上报(此方式虽然可以上报错误,但是我们并不采用这种方式)
方式二:利用Image对象上报(推荐。网站的监控体系都是采用的这种方式)
(new Image()).src = 'http://smyhvae.com/myPath?badjs=msg'; // myPath表示上报的路径
原生Ajax方法实现
// 异步对象
var xhr = new XMLHttpRequest();
// 设置属性
xhr.open('post', 'post.action');
// 如果想要使用post提交数据,必须添加此行
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
// 将数据通过send方法传递
xhr.send('name=fox&age=18');
// 发送并接受返回值
xhr.onreadystatechange = function () {
// 这步为判断服务器是否正确响应
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText);
}
};
头插法实现链表反转
function ReverseList(head) {
var prev = null;
while (head) {
var next = head.next;
head.next = prev;
prev = head;
head = next;
}
return prev;
}
两个有序链表合成一个有序链表
function Merge(pHead1, pHead2) {
if (pHead1 == null) {
return pHead2;
} else if (pHead2 == null) {
return pHead1;
}
var result = null;
if (pHead1.val < pHead2.val) {
result = pHead1;
result.next = Merge(pHead1.next, pHead2);
} else {
result = pHead2;
result.next = Merge(pHead1, pHead2.next);
}
return result;
}
根据前序和中序重建二叉树
function reConstructBinaryTree(pre, vin) {
var result = null;
if (pre.length > 1) {
var root = pre[0];
var vinRootIndex = vin.indexOf(root);
var vinLeft = vin.slice(0, vinRootIndex);
var vinRight = vin.slice(vinRootIndex + 1, vin.length);
pre.shift();
var preLeft = pre.slice(0, vinLeft.length);
var preRight = pre.slice(vinLeft.length, pre.length);
result = {
val: root,
left: reConstructBinaryTree(preLeft, vinLeft),
right: reConstructBinaryTree(preRight, vinRight)
}
} else if(pre.length === 1) {
result = {
val: pre[0],
left: null,
right: null
}
}
return result;
}
二叉树的深度遍历
function depthIterator(root) {
if (root == null) {
return;
}
var stack = []; //深度遍历,利用栈后进先出的特性
stack.push(root);
while (stack.length) {
var current = stack.pop();
System.out.println("--->" + current.val);
if (current.right != null) {
stack.push(current.right); //右子树入栈
}
if (current.left != null) {
stack.push(current.left); //左子树入栈
}
}
}
二叉树的广度遍历
function levelIterator(root) {
if (root == null) {
return;
}
var queue = []; //广度遍历,利用队列先进先出的特性
queue.push(root);
while (queue.length) {
var current = queue.shift();
System.out.println("--->" + current.val);
if (current.left != null) {
queue.push(current.left); //左子树入队
}
if (current.right != null) {
queue.push(current.right); //右子树入队
}
}
}
JS实现快速排序
function quickSort(arr, low, high) {
if (low > high) {
return;
}
var left, right, key;
left = low;
right = high;
key = arr[low];
while (left < right) {
while (key <= arr[right] && left < right) {
right--;
}
arr[left] = arr[right];
while (key >= arr[left] && left < right) {
left++;
}
arr[right] = arr[left];
}
arr[right] = key;
quickSort(arr, low, right - 1);
quickSort(arr, right + 1, high);
}
JS实现二分查找
function binarySearch(arr, key) {
var low = 0;
var high = arr.length - 1;
while (low <= high) {
var mid = parseInt((high + low) / 2);
if (key == arr[mid]) {
return mid;
} else if (key > arr[mid]) {
low = mid + 1;
} else if (key < arr[mid]) {
high = mid - 1;
}
}
return -1;
};