blog

yijie's blog


  • Home

  • Archives

http长连接、cookie、数据协商

Posted on 2018-06-12

1.http长连接

短连接:在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。

长连接:HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:

Connection:keep-alive
在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接需要客户端和服务端都支持长连接。

实验代码:
前端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
img {
width: 400px;
height: 200px;
}
</style>
</head>
<body>
<img src="http://localhost:3000/1.jpg"/>
</body>
</html>

后端代码

1
2
3
4
5
6
7
8
9
10
11
let koa = require('koa');
let app =new koa();
let fs = require('fs');
let path = require('path');
app.use(async (ctx, next) => {
ctx.set('Content-Type', 'image/jpg');
ctx.body = fs.createReadStream(path.join(__dirname, './imgs/jinkesi.jpg'));
});
app.listen(3000, () => {
console.log(`listen 3000 ...`);
})

自己在app.js同级建一个名字为imgs的目录丢进去一张图片,修改一下代码里的图片名称

运行前端代码

1
$ http-server # 自行用npm安装,在这里代理前端的代码

运行后端代码

1
$ node app.js

可以看到response是有一个Connection:keep-alive,表示当前链接,server响应完前端的请求不会立即关闭。

如果多加一些请求,实验环节,多请求一些图片:
前端代码修改为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<img src="http://localhost:3000/1.jpg"/>
<img src="http://localhost:3000/2.jpg"/>
<img src="http://localhost:3000/3.jpg"/>
<img src="http://localhost:3000/4.jpg"/>
<img src="http://localhost:3000/5.jpg"/>
<img src="http://localhost:3000/6.jpg"/>
<img src="http://localhost:3000/7.jpg"/>
<img src="http://localhost:3000/8.jpg"/>
<img src="http://localhost:3000/9.jpg"/>
<img src="http://localhost:3000/10.jpg"/>
<img src="http://localhost:3000/11.jpg"/>
<img src="http://localhost:3000/12.jpg"/>
<img src="http://localhost:3000/13.jpg"/>
<img src="http://localhost:3000/14.jpg"/>

通过选择空白出右键勾上Connection ID选项,可以方便的查看请求使用的tcp链接:

然后访问浏览器查看network:

通过浏览器的network可以看到不同的请求会重复使用一个tcp链接的,也就是说明connection没有立即关闭。

2.cookie

实验代码:
前端:

1
2
3
4
5
6
7
8
<script>
fetch('http://localhost:3000/1.js')
.then((res) => {
return res.text();
}).then(data => {
console.log(data);
})
</script>

后端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let koa = require('koa');
let app =new koa();
app.keys = ['im a newer secret', 'i like turtle'];
app.use(async (ctx, next) => {
ctx.set("Access-Control-Allow-Origin","*");
if (ctx.request.url === '/1.js') {
ctx.cookies.set('name', 'tobi', {
sign: true,
maxAge: 10,
httpOnly:false
});
ctx.body = `console.log("hello everyone")`;
}
});
app.listen(3000, () => {
console.log(`listen 3000 ...`);
})

cookie 的配置选项:

参数 value
max-age 多少秒后过期
expires 过期的时间点
secure 只允许https传输
domain 设置的域名,设置主域名,子域名也可以使用
httpOnly 前端js是否允许操作js
overwrite 是否允许重写

如果max-age 和expires 都没有设置会cookie会在会话关闭消失。

可以通过设置不同的参数给浏览器。

3.数据协商

数据协商:浏览器 和服务器通信的时候,浏览器会告诉服务器我需要什么格式的数据,我希望是接收什么语言,我能解压哪些压缩格式,压缩的代码。
举个例子:

上图中的Accept、Accept-Encoding、Accept-Language 分别告诉浏览器希望接收什么样的消息,什么压缩算法、什么语言。

q=0.9 表示前面的格式代表的权重,权重越大更希望服务器返回权重大的,如果服务器没有,一次往下排。

这些是浏览器根据http协议的规范带上去的,至于服务器端会不会也完全遵守http协议?确不一定。

再看一张服务器返回(response)的图:


1
2
3
4
5
Cache-Control: private #代理服务器不要缓存
Connection: Keep-Alive # 长连接
Content-Type: text/html# 服务器返回的消息的格式,和request里的Accept 对应。
Content-Encoding: gzip # 是服务器返回的压缩方式。
Vary: Accept-Encoding # 如果 url 和Accept-Encoding 相同才使用代理服务器的缓存,否则不用代理服务器的缓存 (一个请求从浏览器到服务器中间可能经过很多的代理服务器,如果服务器设置了s-max-age,会被代理服务器缓存的,相同的请求可能得到的数据来自代理服务器比如nginx)

http cache-Control 缓存小节

Posted on 2018-06-05

cache-control 的值有很多,以下截取一些比较常用的,具体的请参考mdn

参数 value
no-store 每次请求都去服务器获取,不用缓存
no-cache 每次请求必须去服务器验证缓存
max-age 设置客户端缓存多久后失效(单位为s)
s-max-age 设置中间代理服务器缓存多久后失效(单位为s)
Expires 设置到期的时间(单位为Date)
must-revalidate 缓存到期后必须去目标服务器(不会从代理服务器)去验证缓存是否有改变
ETags 一种强校验器,根据请求的内容生成的一个签名值
Last-Modified 一种弱校验器。说它弱是因为它只能精确到秒
private 所有的中间服务器和浏览器都可以缓存
public 只允许浏览器缓存,中间代理服务器不能缓存

上一次response返回ETags,下一次请求header会带上If-None-Match字段和服务器的ETag进行比较
response 返回的Last-Modified ,会在下一次请求header中带上If-Modified-Since和服务器的Last-Modified比较

可以通过服务端(测试用的koa)不同的设置去验证,测试代理服务器可以中间加一层nginx代理3000端口,去设置nginx的缓存验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let koa = require('koa');
let app =new koa();

app.use(async (ctx, next) => {
console.log(ctx.request.url);
ctx.set("Access-Control-Allow-Origin","*");
ctx.set("Access-Control-Allow-Headers", "token");
if (ctx.request.url === '/1.js') {
let etag = '123';
if (ctx.header["if-none-match"] === etag) {
ctx.status = 304;
} else {
ctx.set('Cache-Control', 'max-age=5');
ctx.set('ETag', etag);
ctx.set('Last-Modified', Date.now());
ctx.set('Content-Type', 'application/javascript');
ctx.body = `console.log("hello everyone")`;
}
}
});

客户端测试代码

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src="http://127.0.0.1:3000/1.js"></script>
</body>
</html>

前端通过http-server代理

http cors 简介

Posted on 2018-06-04

跨域问题

首先启动2个server,一个代理前端的代码,一个提供api接口
这里前端我偷懒使用http-server这个模块,
前端写一个简单的ajax请求后端的接口,

前端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
fetch('http://localhost:3000/')
.then(res => res.json())
.then(data => {
console.log(data)
})
.then((err) => {
console.log(`error: ${err}`);
})
</script>
</body>
</html>

后端代码

1
2
3
4
5
6
7
8
9
10
let koa = require('koa');
let app =new koa();

app.use(async (ctx, next) => {
ctx.body = {code: 0, data: `successful`};
});

app.listen(3000, () => {
console.log(`listen 3000 ...`);
})

准备好实验环境,分别启动对应的server,用浏览器访问结果如下:

这是比较经常遇到的跨域问题,解决办法1. 代理 2. 后端处理,为了解决这个问题,修改后端的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
let koa = require('koa');
let app =new koa();

app.use(async (ctx, next) => {
ctx.set({
"Access-Control-Allow-Origin": "*"
});
ctx.body = {code: 0, data: `successful`};
});

app.listen(3000, () => {
console.log(`listen 3000 ...`);
})

再起重启服务器,刷新浏览器

如果把get请求改成post,并且在header里加上个token,结果会怎么样,试一下

修改前端代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
fetch('http://localhost:3000/', {
method: 'POST',
headers: {
'token': '123'
}
})
.then(res => res.json())
.then(data => {
console.log(data)
})
.then((err) => {
console.log(`error: ${err}`);
})
</script>

访问浏览器

是不是很奇怪,平时我们开发vue等单页应用经常用axios在header里面添加token没报过这个错,
为什么这里会报错呢

原因:vue使用了webpack里面的devserver-proxy,帮助我们开发的时候后端代理了,如果在2个不同的域名下就会这样。

所以,在一些浏览器允许的字段白名单之外,都是被浏览器视为不安全的,就算设置了跨域,没设置跨域的heder也是会报错的,解决办法,就是在后端添加进去我们要传的头。

修改后端代码

1
2
3
4
5
app.use(async (ctx, next) => {
ctx.set("Access-Control-Allow-Origin","*");
ctx.set("Access-Control-Allow-Headers", "token");
ctx.body = {code: 0, data: `successful`};
});

再重启服务器,然后刷新页面

再服务器设置了

1
ctx.set("Access-Control-Allow-Origin","*");

之后,并不是万能的,很多浏览器不允许的字段还是不行的,再浏览器预请求会报错。

浏览器允许的字段有下面这些,具体参照mdn

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
------------
GET
HEAD
POST
------------
Accept
Accept-Language
Content-Language
Content-Type (需要注意额外的限制)
DPR
Downlink
Save-Data
Viewport-Width
Width
------------
Content-Type 的值仅限于下列三者之一:
text/plain
multipart/form-data
application/x-www-form-urlencoded

不在这里面的都会进行预请求。

参考第三方库,里面一般都包含这几个

1
2
3
4
5
6
7
8
9
10
ctx.set("Access-Control-Allow-Origin", "*");
// 允许所有的域名
ctx.set("Access-Control-Allow-Methods", "OPTIONS, GET, PUT, POST, DELETE");
// 允许的方法
ctx.set("Access-Control-Allow-Headers", "x-requested-with, accept, origin, content-type");
// 支持的头信息
ctx.set("Access-Control-Allow-Credentials", true);
// 跨域携带cookie,需要保证"Access-Control-Allow-Origin"是服务器有的域名,而不能是"*"
ctx.set("Access-Control-Max-Age", 300);
// 设置300s内不用再次进行预请求也就是再发option请求

http 简介

Posted on 2018-06-04

OSI七层模型:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。

TCP/IP五层模型:物理层、数据链路层、网络层、传输层、应用层。

http 经过多年的发展从最初的0.9、1.0、到目前使用最多的1.1再到了最新的2.0版本。

客户端和服务器通过http建立连接的过程:
http属于应用层,通过tcp/ip的3次握手和服务器建立连接,然后进行数据交互,完成后关闭连接。

从上图Wireshark的结果来看,每次返回的ack总会等于上一次的seq+1;

http1.0:一次建立的tcp链接只能和服务器交互一次就关闭。

http1.1:设置Connection: keep-alive。
一条tcp链接只能串行的和服务器进行交互。

http2.0: 一条tcp链接可以并行的和服务器进行交互。

docker 网络

Posted on 2018-05-30

本节探讨一下docker 的多个容器是怎么通信的
首先准备环境

1
2
$ docker pull busybox
$ sudo yum install -y bridge-utils

启动一个容器

1
$ docker run -itd --name test1 busybox


再启动一个容器添加一个link

1
$ docker run -itd --name test2 --link=test1 busybox


test2可以和test1进行通信说明是可达的
反之看一下test1 能否和test2通信

经过测试test1和test2是不可达的

再看一下test1和test2连接的网桥

继续往下找

test1的ip:

test2的ip:


可以进入test1和test2的容器内部查看ip和这里的一样,可以证明容器自动连接在docker0这个网卡上,默认是无法彼此间通信,需要用–link去指定

如果容器启动的很多,–link的方法很不方便,下面换一种方法,创建一个网桥,所有的容器连接在新建的网桥上

先把容器全部删掉

1
$ docker rm -f test1 test2

先看一下docker network 有哪些命令

下面先创建一个bridge
再启动2个容器并连接到新建的bridge上

再来看一下bridge 和new-bridge

1
$ docker network inspect bridge


没有任何一个容器连接在bridge上

1
$ docker network inspect new-bridge

可以看到test1和test2确实连接在新建的 new-bridge上

再一次进入test1 和test2容器内去ping 对方


可以看到没有任何的容器连接在docker0上

总结: 容器内之间进行通信的方式有2种

  1. 启动的时候用–link 指定 container。
  2. 新建一个网桥,把所有的容器连接在新建的网桥上。

docker 命令介绍

Posted on 2018-05-30

Dockerfile 基本命令

命令 value 解释
FROM centos 基础镜像
LABEL version=’1.0’ 基本信息
RUN yum update && yum install vim 运行的命令
WORKDIR /app 设置镜像的工作目录
ADD file 把本机的文件添加到镜像中
COPY file 把本机的文件拷贝到镜像中
ENV MYSQL_VERSION 设置环境变量
CMD echo ‘123’ 容器启动后默认执行
ENTRYPOINT echo ‘123’ 容器启动时执行的命令

CMD 指定的命令可能被覆盖,ENTRYPOINT指定的不会被覆盖一定会执行

docker 常用的命令

打image
举个例子,先写一个Dockerfile如下:

1
2
3
4
5
6
FROM node
WORKDIR /app
COPY ./app.js app.js
RUN npm install koa -S
EXPOSE 3000
ENTRYPOINT node /app/app.js

打成image

1
$ docker build -t yijie/koa .

运行image生成container

1
$ docker run -d -p 80:3000 --name koaService 0f347d76cb15(image id)

参数可以通过 docker run –help 参看具体意思

参数 解释
-i 交互式操作
-t 终端
-d 守护进程
-p 容器和宿主机的端口映射
–name 容器的名字
-v 持久化数据(这里为了容器内和主机的当前目录共享文件)

把容器内的3000端口的服务映射到了本机的80端口,通过访问本机的80端口来验证是否可以访问到

如果想进入容器内部

docker 安装

Posted on 2018-05-25

环境准备

安装vagrant,选择合适的安装包

安装VirtualBox

创建一个目录,安装centos7 虚拟机

1
2
3
4
5
$ mkdir centos
$ cd centos
$ vagrant init centos/7 # 创建一个Vagrantfile
$ vagrant up #开始下载并启动
$ vagrant ssh

环境(centos7)已经准备好,开始安装docker

安装centos的社区版docker

1
2
3
4
5
6
7
8
9
10
$ sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-selinux \
docker-engine-selinux \
docker-engine
1
2
3
$ sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
1
2
3
$ sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
1
$ sudo yum-config-manager --enable docker-ce-edge
1
$ sudo yum-config-manager --enable docker-ce-test
1
$ sudo yum install docker-ce -y

启动docker

1
$ sudo systemctl start docker

运行一个hello-world镜像

1
$ sudo docker run hello-world

由于网络原因直接拉取docker hub 上的镜像很慢,配置一下官网在中国的源


去掉权限不足

1
2
3
4
5
6
$ sudo groupadd docker
$ sudo gpasswd -a vagrant docker
$ sudo service docker restart
$ exit
$ vagrant ssh
$ docker version

nginx 作为web服务器的常用配置

Posted on 2018-05-17

nginx代理静态页面

1
2
$ cd /etc/nginx/conf.d/
$ vim default.conf

修改location

1
2
3
4
location / {
root /opt/app/code; # 修改为你的静态文件的路径
index index.html index.htm;
}

保存退出

1
2
3
4
5
$ nginx -t  #检查配置有无语法错误
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

$ nginx -s reload

在浏览器访问nginx服务器

图1

nginx代理静态页面的缓存

图2


图3

和图1比较,ETag和Last-Modified没有改变,服务器决策后返回304

配置一下nginx加一个过期时间

1
2
$ cd /etc/nginx/conf.d
$ vim default.conf
1
2
3
4
5
location / {
root /opt/app/code;
expires 2h; #加了一行设置过期时间
index index.html index.htm;
}
1
2
$ nginx -t
$ nginx -s reload

再次用浏览器访问

图4

从图中可以看到多了Cache-Control: max-age=7200, 7200s正好是服务器设置的2h

note: 刷新页面发现request header中的Cache-Control:max-age=0
这个属于浏览器的行为,每次刷新页面正常有设置的缓存2h,应该不请求服务器,事实上因为request_header中的max-age=0还是会发一次请求的再让ETag去和服务器比较,决策后返回的还是304

设置跨越

1
$ vim /etc/nginx/conf.d/default.conf
1
2
3
4
5
6
7
location / {
root /opt/app/code;
expires 2h;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
index index.html index.htm;
}
1
2
$ nginx -t
$ nginx -s reload

nginx的反向代理

1
2
$ cd /etc/nginx/conf.d
$ vim demo.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
server {
listen 8000;
server_name 112.74.13.145;
server_name_in_redirect off;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering off;
proxy_pass http://112.74.13.145:2000;
proxy_redirect off;
}
}
1
2
$ nginx -t
$ nginx -s reload

注释:2000是docker容器里的nginx,8000是云主机的nginx(相当于2台服务器)
通过浏览器访问

5. 配置https

配置文件如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
upstream demo {
server 127.0.0.1:3001;#ip,port可以随便修改为合适的ip,port, 这里多写几个可以做负载均衡
}

server {
listen 443;
server_name 192.168.1.2; #服务器的ip
ssl on;
ssl_certificate /ssl/www/www.crt;#填写具体的文件路径
ssl_certificate_key /ssl/www/www.key;#填写具体的文件路径
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
server_name_in_redirect off;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering off;
proxy_pass http://demo;
proxy_redirect off;
}
}

nginx 安装 for centos7.x

Posted on 2018-05-14

打开 nginx download 页面

创建文件 nginx.repo

1
$ vim /etc/yum.repos.d/nginx.repo

添加配置

1
2
3
4
5
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1

创建nginx_signing.key

1
$ vim nginx_signing.key

添加key的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2.0.22 (GNU/Linux)

mQENBE5OMmIBCAD+FPYKGriGGf7NqwKfWC83cBV01gabgVWQmZbMcFzeW+hMsgxH
W6iimD0RsfZ9oEbfJCPG0CRSZ7ppq5pKamYs2+EJ8Q2ysOFHHwpGrA2C8zyNAs4I
QxnZZIbETgcSwFtDun0XiqPwPZgyuXVm9PAbLZRbfBzm8wR/3SWygqZBBLdQk5TE
fDR+Eny/M1RVR4xClECONF9UBB2ejFdI1LD45APbP2hsN/piFByU1t7yK2gpFyRt
97WzGHn9MV5/TL7AmRPM4pcr3JacmtCnxXeCZ8nLqedoSuHFuhwyDnlAbu8I16O5
XRrfzhrHRJFM1JnIiGmzZi6zBvH0ItfyX6ttABEBAAG0KW5naW54IHNpZ25pbmcg
a2V5IDxzaWduaW5nLWtleUBuZ2lueC5jb20+iQE+BBMBAgAoAhsDBgsJCAcDAgYV
CAIJCgsEFgIDAQIeAQIXgAUCV2K1+AUJGB4fQQAKCRCr9b2Ce9m/YloaB/9XGrol
kocm7l/tsVjaBQCteXKuwsm4XhCuAQ6YAwA1L1UheGOG/aa2xJvrXE8X32tgcTjr
KoYoXWcdxaFjlXGTt6jV85qRguUzvMOxxSEM2Dn115etN9piPl0Zz+4rkx8+2vJG
F+eMlruPXg/zd88NvyLq5gGHEsFRBMVufYmHtNfcp4okC1klWiRIRSdp4QY1wdrN
1O+/oCTl8Bzy6hcHjLIq3aoumcLxMjtBoclc/5OTioLDwSDfVx7rWyfRhcBzVbwD
oe/PD08AoAA6fxXvWjSxy+dGhEaXoTHjkCbz/l6NxrK3JFyauDgU4K4MytsZ1HDi
MgMW8hZXxszoICTTiQEcBBABAgAGBQJOTkelAAoJEKZP1bF62zmo79oH/1XDb29S
YtWp+MTJTPFEwlWRiyRuDXy3wBd/BpwBRIWfWzMs1gnCjNjk0EVBVGa2grvy9Jtx
JKMd6l/PWXVucSt+U/+GO8rBkw14SdhqxaS2l14v6gyMeUrSbY3XfToGfwHC4sa/
Thn8X4jFaQ2XN5dAIzJGU1s5JA0tjEzUwCnmrKmyMlXZaoQVrmORGjCuH0I0aAFk
RS0UtnB9HPpxhGVbs24xXZQnZDNbUQeulFxS4uP3OLDBAeCHl+v4t/uotIad8v6J
SO93vc1evIje6lguE81HHmJn9noxPItvOvSMb2yPsE8mH4cJHRTFNSEhPW6ghmlf
Wa9ZwiVX5igxcvaIRgQQEQIABgUCTk5b0gAKCRDs8OkLLBcgg1G+AKCnacLb/+W6
cflirUIExgZdUJqoogCeNPVwXiHEIVqithAM1pdY/gcaQZmIRgQQEQIABgUCTk5f
YQAKCRCpN2E5pSTFPnNWAJ9gUozyiS+9jf2rJvqmJSeWuCgVRwCcCUFhXRCpQO2Y
Va3l3WuB+rgKjsQ=
=EWWI
-----END PGP PUBLIC KEY BLOCK-----

加载key

1
$ sudo rpm --import nginx_signing.key

安装nginx

1
$ yum install nginx -y

启动nginx

1
$ nginx

测试nginx

1
$ curl localhost

结果如下,安装成功

Vue面试问题收集

Posted on 2018-05-14

为什么选择Vue框架?

  1. 学习成本比较低
  2. 流行程度和作者对框架的维护热度高
  3. 文档完善、生态圈庞大、bug修复速度快

Vue的双向绑定是如何实现的?

基本原理: 数据驱动页面,页面映射数据

核心API: 观察者模式

监听着Observer 监听data变化, data变化会触发Object.defineProperty()的set函数,通知观察者列表Dep, Wacher订阅Dep,Dep接到通知后回调Watcher执行update函数,更新View

observer

有没有使用过css module, 基本原理是什么, vue 该如何做?

css module的工作原理就是把一个类名编译成哈希字符串,然后在引用的时候直接使用这个哈希字符串,进而保证相同的类名根据不同的路径和组件名称得到不同的值,保证了最终的类名隔离。

vue 在vue-loader中的配置开启css module

1
2
modules: true,
localIdentName: '[path][name]---[local]---[hash:base64:5]'

在文件中style标签上加module属性

对于父类声明的类名,在子组件内,css module是不处理的,想用必须显示调用类名($style.类名)

开启css module之后引用第三方样式库?

@import 引入

如果在一个组件内引用了第三方库,想修改第三方库的样式又不想在其他影响到其他页面的引用,
可以使用深度作用选择器 >>>

1
2
3
<style scoped>
.a >>> .b { /* ... */ }
</style>

vue的安装包有几个版本,遇到问题如何解决?

不同构建版本的解释

vue不同版本的解释

1
2
3
4
5
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
},

你的项目有什么特色?

自适应方案、模块化设计(css、 js)

解决过什么问题,怎么解决?用的技术方案?

自适应: 自适应方案在移动端要适配多种机型, 通常使用meda+rem 的方案, 缺点是media是有优先级的,多个media有优先级覆盖不好容易导致失效,设备太多测试困难,不具备通用性。

在vue中使用pm2rem-loader, 在开发中只需要关心我们熟悉的px单位,pm2rem-loader会自动把px转成rem,在搭配hotcss.js自动的计算font-size,自动的修改根节点的rem。

项目的改进空间?

  1. 如果上线可以开启nginx的gzip压缩进一步压缩体积,提高访问速度,这次我托管在github没有做
  2. 可以使用vue的异步加载方案,提高首屏的加载速度, 因为本次项目不大,就没有使用,小项目使用异步加载会打包出多个js文件需要多次访问,同时也意味着多几个http请求,小项目http请求的开销远比多加载一点js的消耗要大,如果文件达到几M就可以使用异步加载,否则可以不用(个人观点)。

前端的路由是什么原理?

1
2
3
history    pushstate、onpopstate

hash location.hash、hashchange

参考文章: 快乐动起来

12

yijie

记录日常的学习

11 posts
© 2018 yijie
Powered by Hexo
|
Theme — NexT.Gemini v5.1.4