diff --git a/.vuepress/header.json b/.vuepress/header.json
index 73b90a41..b0c7e59a 100644
--- a/.vuepress/header.json
+++ b/.vuepress/header.json
@@ -220,11 +220,23 @@
],
[
"http/330",
- "如何避免 CDN 为 PC 端缓存移动端页面"
+ "如何避免 CDN 为 PC 端缓存移动端页面⭐️"
],
[
"http/360",
"在 node 端如何向服务器上传文件"
+ ],
+ [
+ "http/363",
+ "什么情况下会发送 OPTIONS 请求⭐️"
+ ],
+ [
+ "http/364",
+ "CORS 如果需要指定多个域名怎么办⭐️"
+ ],
+ [
+ "http/366",
+ "既然 cors 配置可以做跨域控制,那可以防止 CSRF 攻击吗 ⭐️"
]
]
},
@@ -370,7 +382,7 @@
],
[
"network/135",
- "ssh 的原理是什么"
+ "ssh 的原理是什么⭐️"
],
[
"network/174",
@@ -387,6 +399,10 @@
[
"network/184",
"tcp 中 time_wait 堆积过多会有什么问题,为什么它超时时间这么长"
+ ],
+ [
+ "network/365",
+ "localhost 与 127.0.0.1 有什么区别⭐️"
]
]
},
@@ -856,6 +872,14 @@
[
"server/353",
"如何实现一个 timeout 的中间件"
+ ],
+ [
+ "server/363",
+ "什么情况下会发送 OPTIONS 请求⭐️"
+ ],
+ [
+ "server/368",
+ "如何获取当前系统中的在线用户数 (并发用户数)⭐️"
]
]
},
@@ -938,7 +962,7 @@
],
[
"css/179",
- "如何使用 css 写一个有 3D 效果的立方体"
+ "如何使用 css 写一个有 3D 效果的立方体⭐️"
],
[
"css/185",
@@ -970,7 +994,7 @@
],
[
"css/308",
- "如何实现左右固定,中间自适应布局"
+ "如何实现左右固定,中间自适应布局⭐️"
],
[
"css/309",
@@ -978,7 +1002,7 @@
],
[
"css/311",
- "简述下 css specificity"
+ "简述下 css specificity⭐️"
],
[
"css/317",
@@ -1018,7 +1042,11 @@
],
[
"css/342",
- "伪类与伪元素有什么区别"
+ "伪类与伪元素有什么区别⭐️"
+ ],
+ [
+ "css/369",
+ "css 如何匹配前N个子元素及最后N个子元素⭐️"
]
]
},
@@ -1047,6 +1075,10 @@
"dom/215",
"input 中监听值的变化是在监听什么事件⭐️"
],
+ [
+ "dom/269",
+ "CSP 是干什么用的了⭐️"
+ ],
[
"dom/286",
"prefetch 与 preload 的区别是什么⭐️"
@@ -1058,6 +1090,10 @@
[
"dom/315",
"在浏览器中如何监听剪切板中内容⭐️"
+ ],
+ [
+ "dom/367",
+ "js 动画和 css 动画那个性能比较好"
]
]
},
@@ -1259,7 +1295,7 @@
],
[
"js/361",
- "js 如何全部替代一个子串为另一个子串"
+ "js 如何全部替代一个子串为另一个子串⭐️"
]
]
},
@@ -1634,7 +1670,7 @@
],
[
"前端工程化/192",
- "什么是 Open Graph 协议,用来做什么"
+ "什么是 Open Graph 协议,用来做什么⭐️"
],
[
"前端工程化/193",
@@ -1915,6 +1951,10 @@
[
"open/264",
"当一个排期五天的任务需要在两天后上线如何解决"
+ ],
+ [
+ "open/340",
+ "你做前端有多少时间花在写 css 上"
]
]
}
diff --git a/Readme.md b/Readme.md
index 5a540d01..c9302b39 100644
--- a/Readme.md
+++ b/Readme.md
@@ -27,6 +27,12 @@
### [DevOps](https://q.shanyue.tech/devops/)
### [开放式问题](https://q.shanyue.tech/open/)
+## 大厂内推
+
++ [阿里-供应链平台事业部-前端-校招/社招](https://q.shanyue.tech/infer/ali-ascp.html)
++ [字节-视频架构组-前端-社招](https://q.shanyue.tech/infer/toutiao-media-arch.html)
++ [腾讯-CSIG智慧零售-前端-社招](https://q.shanyue.tech/infer/tencent-csig.html)
+
## 大厂面经
### 阿里
@@ -53,12 +59,6 @@
更多面经请转至 [大厂面经大全](https://q.shanyue.tech/interviews/fe.html)
-## 大厂内推
-
-+ [阿里-供应链平台事业部-前端-校招/社招](https://q.shanyue.tech/infer/ali-ascp.html)
-+ [字节-视频架构组-前端-社招](https://q.shanyue.tech/infer/toutiao-media-arch.html)
-+ [腾讯-CSIG智慧零售-前端-社招](https://q.shanyue.tech/infer/tencent-csig.html)
-
## 大厂内推与大厂面经推送
关注公众号【互联网大厂招聘】,将持续推送大厂的面试经验与大厂的内推,直达招聘负责人或团队负责人
@@ -67,7 +67,7 @@
-如果你想在网站及公众号上发布招聘,请添加我的微信 `shanyue-94`,我将与你在以下几个方面进行讨论,并共同拟定模拟面试题在我公众号上发布招聘信息
+如果你想在网站及公众号上发布招聘,请添加我的微信 `shanyue94`,我将与你在以下几个方面进行讨论,并共同拟定模拟面试题在我公众号上发布招聘信息
1. 业务描述,及其业务发展与前景
1. 职位描述,及其技术侧重于偏向
diff --git a/base/Readme.md b/base/Readme.md
index 0a928a5c..8bef2b9a 100644
--- a/base/Readme.md
+++ b/base/Readme.md
@@ -90,4 +90,8 @@
+ [【Q329】什么是一致性哈希,可以解决什么问题](data-structure/332.html)
+ [【Q343】如何查找地图中某个点两公里内的餐厅](data-structure/346.html)
+ [【Q344】如何列出所有已合并到 master 的分支并删除](git/347.html)
-+ [【Q356】在 node 端如何向服务器上传文件](http/360.html)
\ No newline at end of file
++ [【Q356】在 node 端如何向服务器上传文件](http/360.html)
++ [【Q358】什么情况下会发送 OPTIONS 请求](http/363.html)
++ [【Q359】CORS 如果需要指定多个域名怎么办](http/364.html)
++ [【Q360】localhost 与 127.0.0.1 有什么区别](network/365.html)
++ [【Q361】既然 cors 配置可以做跨域控制,那可以防止 CSRF 攻击吗 ](http/366.html)
\ No newline at end of file
diff --git a/base/http/328.md b/base/http/328.md
index 71a9f21e..5d515fb7 100644
--- a/base/http/328.md
+++ b/base/http/328.md
@@ -12,9 +12,9 @@
- `Access-Control-Allow-Origin`
- `Access-Control-Allow-Methods`
-- `Access-Control-Expose-Headers`
- `Access-Control-Allow-Headers`
-- `Access-Control-Max-Age`
- `Access-Control-Allow-Credentials`
+- `Access-Control-Expose-Headers`
+- `Access-Control-Max-Age`
关于如何写一个 `cors` 的中间件可以参考 [koajs/cors](https://github.com/koajs/cors)
\ No newline at end of file
diff --git a/base/http/330.md b/base/http/330.md
index 117322fb..4ea1d2ea 100644
--- a/base/http/330.md
+++ b/base/http/330.md
@@ -6,5 +6,47 @@
欢迎在 Issue 中交流与讨论: [Issue 330](https://github.com/shfshanyue/Daily-Question/issues/330)
:::
+::: tip Author
+回答者: [shfshanyue](https://github.com/shfshanyue)
+:::
+
+如果 PC 端和移动端是一套代码则不会出现这个问题。**这个问题出现在 PC 端和移动端是两套代码,却共用一个域名。**
+
+使用 `nginx` 配置如下,根据 UA 判断是否移动端,而走不同的逻辑 (判断UA是否移动端容易出问题)
+
+``` conf
+location / {
+ // 默认 PC 端
+ root /usr/local/website/web;
+
+ # 判断 UA,访问移动端
+ if ( $http_user_agent ~* "(Android|webOS|iPhone|iPad|BlackBerry)" ){
+ root /usr/local/website/mobile;
+ }
+
+ index index.html index.htm;
+}
+```
+
+解决方案通常使用 `Vary` 响应头,来控制 CDN 对不同请求头的缓存。
+
+**此处可以使用 `Vary: User-Agent` ,代表如果 User-Agent 不一样,则重新发起请求,而非从缓存中读取页面**
+
+``` txt
+Vary: User-Agent
+```
+
+当然,`User-Agent` 实在过多,此时缓存失效就会过多。
+
+## 简答
+
+使用 `Vary: User-Agent`,根据 UA 进行缓存。
+
+``` txt
+Vary: User-Agent
+```
+但最好不要出现这种情况,PC 端和移动端如果是两套代码,建议用两个域名,理由如下
+1. `nginx` 判断是否移动端容易出错
+1. 对缓存不友好
diff --git a/base/http/363.md b/base/http/363.md
new file mode 100644
index 00000000..a794b355
--- /dev/null
+++ b/base/http/363.md
@@ -0,0 +1,16 @@
+# 什么情况下会发送 OPTIONS 请求
+
+
+
+::: tip Issue
+ 欢迎在 Issue 中交流与讨论: [Issue 363](https://github.com/shfshanyue/Daily-Question/issues/363)
+:::
+
+::: tip Author
+回答者: [hedongxiaoshimei](https://github.com/hedongxiaoshimei)
+:::
+
+[搬运地址](https://blog.csdn.net/kahhy/article/details/81563063)
+1:请求的方法不是GET/HEAD/POST
+2:POST请求的Content-Type 异常
+3:请求设置了自定义的header字段
diff --git a/base/http/364.md b/base/http/364.md
new file mode 100644
index 00000000..bdf27b4d
--- /dev/null
+++ b/base/http/364.md
@@ -0,0 +1,91 @@
+# CORS 如果需要指定多个域名怎么办
+
+
+
+::: tip Issue
+ 欢迎在 Issue 中交流与讨论: [Issue 364](https://github.com/shfshanyue/Daily-Question/issues/364)
+:::
+
+::: tip Author
+回答者: [shfshanyue](https://github.com/shfshanyue)
+:::
+
+`CORS` 通过控制 `Access-Control-Allow-Origin` 控制哪些域名可以共享资源,取值如下
+
+``` bash
+Access-Control-Allow-Origin: | *
+```
+
+其中 `*` 代表所有域名,`origin` 代表指定特定域名,那如何设置多个域名了?
+
+此时需要通过代码实现,**根据请求头中的 `Origin` 来设置响应头 `Access-Control-Allow-Origin`**,那 Origin 又是什么东西?
+
+## 请求头: Origin
+
+并不是所有请求都会自动带上 `Origin`,在浏览器中带 `Origin` 的逻辑如下
+
+1. 如果存在跨域,则带上 `Origin`,值为当前域名
+1. 如果不存在跨域,则不带 `Origin`
+
+逻辑理清楚后,关于服务器中对于 `Access-Control-Allow-Origin` 设置多域名的逻辑也很清晰了
+
+1. 如果请求头不带有 `Origin`,证明未跨域,则不作任何处理
+1. 如果请求头带有 `Origin`,证明跨域,根据 `Origin` 设置相应的 `Access-Control-Allow-Origin: `
+
+使用伪代码实现如下:
+
+``` js
+// 获取 Origin 请求头
+const requestOrigin = ctx.get('Origin');
+
+// 如果没有,则跳过
+if (!requestOrigin) {
+ return await next();
+}
+
+// 设置响应头
+ctx.set('Access-Control-Allow-Origin', requestOrigin)
+```
+
+## Vary: Origin
+
+此时可以给多个域名控制 CORS,但此时假设有两个域名访问 `static.shanyue.tech` 的跨域资源
+
+1. `foo.shanyue.tech`,响应头中返回 `Access-Control-Allow-Origin: foo.shanyue.tech`
+1. `bar.shanyue.tech`,响应头中返回 `Access-Control-Allow-Origin: bar.shanyue.tech`
+
+看起来一切正常,但如果中间有缓存怎么办?
+
+1. `foo.shanyue.tech`,响应头中返回 `Access-Control-Allow-Origin: foo.shanyue.tech`,被 CDN 缓存
+1. **`bar.shanyue.tech`,因由缓存,响应头中返回 `Access-Control-Allow-Origin: foo.shanyue.tech`,跨域出现问题**
+
+此时,`Vary: Origin` 就上场了,代表为不同的 `Origin` 缓存不同的资源
+
+## 总结 (简要答案)
+
+CORS 如何指定多个域名?
+
+**根据请求头中的 `Origin` 来设置响应头 `Access-Control-Allow-Origin`**,思路如下
+
+1. 总是设置 `Vary: Origin`,避免 CDN 缓存破坏 CORS 配置
+1. 如果请求头不带有 `Origin`,证明未跨域,则不作任何处理
+1. 如果请求头带有 `Origin`,证明浏览器访问跨域,根据 `Origin` 设置相应的 `Access-Control-Allow-Origin: `
+
+使用伪代码实现如下
+
+``` js
+// 获取 Origin 请求头
+const requestOrigin = ctx.get('Origin');
+
+ctx.set('Vary', 'Origin')
+
+// 如果没有,则跳过
+if (!requestOrigin) {
+ return await next();
+}
+
+// 设置响应头
+ctx.set('Access-Control-Allow-Origin', requestOrigin)
+```
+
+> 相关问题:[如何避免 CDN 为 PC 端缓存移动端页面](https://github.com/shfshanyue/Daily-Question/issues/330)
\ No newline at end of file
diff --git a/base/http/366.md b/base/http/366.md
new file mode 100644
index 00000000..8b8b82d0
--- /dev/null
+++ b/base/http/366.md
@@ -0,0 +1,16 @@
+# 既然 cors 配置可以做跨域控制,那可以防止 CSRF 攻击吗
+
+
+
+::: tip Issue
+ 欢迎在 Issue 中交流与讨论: [Issue 366](https://github.com/shfshanyue/Daily-Question/issues/366)
+:::
+
+::: tip Author
+回答者: [shfshanyue](https://github.com/shfshanyue)
+:::
+
+**对 CORS 一点用也没有**
+
+1. **`form` 提交不通过 `CORS` 检测**,你可以在本地进行测试
+1. 即使通过 `xhr` 及 `fetch` 进行提交被 CORS 拦住,**但是对于简单请求而言,请求仍被发送**,已造成了攻击
diff --git a/base/http/Readme.md b/base/http/Readme.md
index ffa7abd2..d0fe64d3 100644
--- a/base/http/Readme.md
+++ b/base/http/Readme.md
@@ -31,4 +31,7 @@
+ [【Q301】base64 由哪64个字符构成](303.html)
+ [【Q325】关于 cors 的响应头有哪些](328.html)
+ [【Q327】如何避免 CDN 为 PC 端缓存移动端页面](330.html)
-+ [【Q356】在 node 端如何向服务器上传文件](360.html)
\ No newline at end of file
++ [【Q356】在 node 端如何向服务器上传文件](360.html)
++ [【Q358】什么情况下会发送 OPTIONS 请求](363.html)
++ [【Q359】CORS 如果需要指定多个域名怎么办](364.html)
++ [【Q361】既然 cors 配置可以做跨域控制,那可以防止 CSRF 攻击吗 ](366.html)
\ No newline at end of file
diff --git a/base/linux/4.md b/base/linux/4.md
index b1d18be7..6b841672 100644
--- a/base/linux/4.md
+++ b/base/linux/4.md
@@ -38,6 +38,20 @@ Linux 3.10.0-957.21.3.el7.x86_64 (shanyue) 11/04/19 _x86_64_
20:47:41 0 3506 0.00 0.00 139940 6984 0.18 vim
```
-当然,也可以使用万能的 `htop` 命令
+`pidstat` 是属于 `sysstat` 下的 linux 性能工具,但在 mac 中,如何定位内存的变化?此时可以使用万能的 `top/htop`
-参考: [linux 各项监控指标小记](https://shanyue.tech/op/linux-monitor)
\ No newline at end of file
+ ``` bash
+ $ htop -p 31796
+ ```
+
+
+
+## 总结
+
+简而言之,有以下三个命令
+
+1. `pidstat -r`
+1. `htop/top -p`
+1. `ps -O rss -p`
+
+关于更多指标的监控可以参考我的文章: [linux 各项监控指标小记](https://shanyue.tech/op/linux-monitor.html)
\ No newline at end of file
diff --git a/base/linux/71.md b/base/linux/71.md
index d1dccbdc..fd9deb46 100644
--- a/base/linux/71.md
+++ b/base/linux/71.md
@@ -10,12 +10,36 @@
回答者: [shfshanyue](https://github.com/shfshanyue)
:::
-使用 `sed` 或者 `head`/`tail`,以要输出第100行为例
+通常使用 `sed` 命令打印特定行,如
+``` bash
+# -n: 按特定格式打印
+# 100p: 指打印第一百行
+$ sed -n 100p Readme.md
```
-sed -n 100p Readme.md
-head -100 Readme.md | tail -1
+但 `sed` 打印的本领,远不止于此,除了打印特定行,还可以打印一段范围的行,如
+
+``` bash
+# 打印文件中第 100-120 行
+$ sed -n 100,120p Readme.md
+
+# 打印文件中第 100-120 行
+$ sed -n 100,+20p Readme.md
+```
+
+还有一种本办法,`head`/`tail` 的组合命令,以要输出第100行为例
+
+``` bash
+# 输出前100行,再通过 pipe,输出最后一行
+$ head -100 Readme.md | tail -1
```
-关于 `sed` 更多的用法可以参考我的文章: [sed 命令详解及示例](https://shanyue.tech/op/linux-sed.html#sed-%E5%91%BD%E4%BB%A4%E8%AF%A6%E8%A7%A3)
\ No newline at end of file
+关于 `sed` 更多的用法可以参考我的文章: [sed 命令详解及示例](https://shanyue.tech/op/linux-sed.html)
+
+## 总结
+
+两种方法
+
+1. `sed -n 100p Readme.md`
+1. `head -100 Readme.md | tail -1`
\ No newline at end of file
diff --git a/base/network/135.md b/base/network/135.md
index ef837298..c1854bc2 100644
--- a/base/network/135.md
+++ b/base/network/135.md
@@ -6,5 +6,8 @@
欢迎在 Issue 中交流与讨论: [Issue 135](https://github.com/shfshanyue/Daily-Question/issues/135)
:::
+::: tip Author
+回答者: [hedongxiaoshimei](https://github.com/hedongxiaoshimei)
+:::
-
+搬运 [图解SSH原理](https://www.jianshu.com/p/33461b619d53)
\ No newline at end of file
diff --git a/base/network/365.md b/base/network/365.md
new file mode 100644
index 00000000..74592bfe
--- /dev/null
+++ b/base/network/365.md
@@ -0,0 +1,15 @@
+# localhost 与 127.0.0.1 有什么区别
+
+
+
+::: tip Issue
+ 欢迎在 Issue 中交流与讨论: [Issue 365](https://github.com/shfshanyue/Daily-Question/issues/365)
+:::
+
+::: tip Author
+回答者: [hedongxiaoshimei](https://github.com/hedongxiaoshimei)
+:::
+
+localhost 可以更改后指向其它地址。
+127.0.0.1 是约定的本机IP。
+类似互联网中域名与服务器IP的关系。
\ No newline at end of file
diff --git a/base/network/Readme.md b/base/network/Readme.md
index 9da64743..64f4d7e4 100644
--- a/base/network/Readme.md
+++ b/base/network/Readme.md
@@ -11,4 +11,5 @@
+ [【Q173】简述 UDP socket 建立的过程](174.html)
+ [【Q174】TCP 三次握手发生在 socket 建立的哪一步](175.html)
+ [【Q182】简述 TCP 的四次挥手,三次挥手可以吗](183.html)
-+ [【Q183】tcp 中 time_wait 堆积过多会有什么问题,为什么它超时时间这么长](184.html)
\ No newline at end of file
++ [【Q183】tcp 中 time_wait 堆积过多会有什么问题,为什么它超时时间这么长](184.html)
++ [【Q360】localhost 与 127.0.0.1 有什么区别](365.html)
\ No newline at end of file
diff --git a/fe/Readme.md b/fe/Readme.md
index 1d6d891e..32182360 100644
--- a/fe/Readme.md
+++ b/fe/Readme.md
@@ -109,7 +109,7 @@
+ [【Q264】当 Node 应用发生 gc 时,如何监控](node/266.html)
+ [【Q265】Node 应用中如何查看 gc 的日志](node/267.html)
+ [【Q266】bind 与 call/apply 的区别是什么](js/268.html)
-+ [【Q267】CSP 是干什么用的了](js/269.html)
++ [【Q267】CSP 是干什么用的了](dom/269.html)
+ [【Q268】你如何看待 serverless](前端工程化/270.html)
+ [【Q269】什么是 XSS 攻击,如何避免](前端工程化/271.html)
+ [【Q271】react hooks 的原理是什么](react/273.html)
@@ -163,4 +163,6 @@
+ [【Q354】在 node 中如何判断一个对象是 stream](node/357.html)
+ [【Q355】什么是 Iterable 对象,与 Array 有什么区别](js/358.html)
+ [【Q356】在 node 端如何向服务器上传文件](node/360.html)
-+ [【Q357】js 如何全部替代一个子串为另一个子串](js/361.html)
\ No newline at end of file
++ [【Q357】js 如何全部替代一个子串为另一个子串](js/361.html)
++ [【Q362】js 动画和 css 动画那个性能比较好](dom/367.html)
++ [【Q364】css 如何匹配前N个子元素及最后N个子元素](css/369.html)
\ No newline at end of file
diff --git a/fe/css/179.md b/fe/css/179.md
index ed8699fb..89701f31 100644
--- a/fe/css/179.md
+++ b/fe/css/179.md
@@ -6,5 +6,89 @@
欢迎在 Issue 中交流与讨论: [Issue 179](https://github.com/shfshanyue/Daily-Question/issues/179)
:::
+::: tip Author
+回答者: [lihan1k](https://github.com/lihan1k)
+:::
+
+`
+
1
+
2
+
3
+
4
+
5
+
6
+
`
+`* {
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ perspective: none;
+ perspective-origin: 50% 50%;
+}
+
+.warp {
+ width: 500px;
+ height: 500px;
+ margin: 100px auto;
+
+ position: relative;
+
+ transform-style: preserve-3d;
+
+ transform: rotateX(45deg) rotateY(45deg);
+
+ animation: play 5s linear infinite;
+}
+
+.box {
+ width: 200px;
+ height: 200px;
+ border: 2px solid #ccc;
+
+ text-align: center;
+ line-height: 200px;
+ font-size: 150px;
+ font-weight: bold;
+ color: #fff;
+
+ position: absolute;
+ top: 150px;
+ left: 150px;
+}
+
+.box1 {
+ background: rgba(135,135,135,.3);
+ transform: rotateY(90deg) translateZ(100px);
+}
+
+.box2 {
+ background: rgba(135,0,255,.3);
+ transform: rotateY(90deg) translateZ(-100px);
+}
+
+.box3 {
+ background: rgba(255,125,125,.3);
+ transform: rotateX(90deg) translateZ(-100px);
+}
+
+.box4 {
+ background: rgba(125,255,125,.3);
+ transform: rotateX(90deg) translateZ(100px);
+}
+
+.box5 {
+ background: rgba(30,150,189,.3);
+ transform: translateZ(100px);
+}
+.box6 {
+ background: rgba(169,150,189,.3);
+ transform: translateZ(-100px);
+}
+@keyframes play {
+ from{ transform: rotateX(0) rotateY(0) rotateZ(0);}
+ to {transform: rotateX(360deg) rotateY(180deg) rotateZ(90deg);}
+}`
\ No newline at end of file
diff --git a/fe/css/18.md b/fe/css/18.md
index 6b8eca21..1da84367 100644
--- a/fe/css/18.md
+++ b/fe/css/18.md
@@ -7,27 +7,61 @@
:::
::: tip Author
-回答者: [zhaochongzi](https://github.com/zhaochongzi)
+回答者: [shfshanyue](https://github.com/shfshanyue)
:::
-css---
- .box{
- width:100%;;
- height:100%;
- display:flex;
- }
- .one{
- width:300px;
- height:300px;
- background-color: #afa;
- }
- .two{
- flex:1;
- height:300px;
- background-color: #ae5aca;
- }
-html----
-
\ No newline at end of file
+使用 `flex` 布局,左侧 `300px`,右侧 `flex-grow: 1`。`pug` 代码及 `css` 代码示例如下
+
+``` pug
+.container
+ .left
+ .main
+```
+
+``` css
+.container {
+ display: flex;
+}
+
+.left {
+ flex-basis: 300px;
+}
+
+.main {
+ flex-grow: 1;
+}
+```
+
+此处看起来比较圆满了,其实还有一个缺陷: **如果 .main 区域过大挤压 .left 区域怎么办**,此时还需要加一个禁止挤压
+
+``` css
+.left {
+ flex-basis: 300px;
+ flex-shrink: 0;
+}
+```
+
+## 总结
+
+使用 `flex` 进行如下布局
+
+``` pug
+.container
+ .left
+ .main
+```
+
+``` css
+.container {
+ display: flex;
+}
+
+.left {
+ flex-basis: 300px;
+ flex-shrink: 0;
+}
+
+.main {
+ flex-grow: 1;
+}
+```
\ No newline at end of file
diff --git a/fe/css/308.md b/fe/css/308.md
index a8b2787c..590514ab 100644
--- a/fe/css/308.md
+++ b/fe/css/308.md
@@ -6,5 +6,36 @@
欢迎在 Issue 中交流与讨论: [Issue 308](https://github.com/shfshanyue/Daily-Question/issues/308)
:::
+::: tip Author
+回答者: [shfshanyue](https://github.com/shfshanyue)
+:::
+
+可以参考 [【Q017】css 如何实现左侧固定300px,右侧自适应的布局](https://github.com/shfshanyue/Daily-Question/issues/18)
+
+
+``` pug
+.container
+ .left
+ .main
+ .right
+```
+
+``` css
+.container {
+ display: flex;
+}
+
+.left {
+ flex-basis: 300px;
+ flex-shrink: 0;
+}
+.right {
+ flex-basis: 300px;
+ flex-shrink: 0;
+}
+.main {
+ flex-grow: 1;
+}
+```
\ No newline at end of file
diff --git a/fe/css/309.md b/fe/css/309.md
index c3fc7689..7518bc08 100644
--- a/fe/css/309.md
+++ b/fe/css/309.md
@@ -10,7 +10,12 @@
回答者: [shfshanyue](https://github.com/shfshanyue)
:::
-通过 `css3` 中选择器 `:nth-child` 来实现
+通过 `css3` 中伪类 `:nth-child` 来实现。其中 `:nth-child(an+b)` 匹配下标 `{ an + b; n = 0, 1, 2, ...} ` 且结果为整数的子元素
+
++ `nth-child(2n)`/`nth-child(even)`: 双行样式
++ `nth-child(2n+1)`/`nth-child(odd)`: 单行样式
+
+其中 `tr` 在表格中代表行,实现表格中单双行样式就很简单了:
``` css
tr:nth-child(2n) {
@@ -21,4 +26,9 @@ tr:nth-child(2n) {
tr:nth-child(2n+1) {
background-color: blue;
}
-```
\ No newline at end of file
+```
+
+同理:
+
+1. 如何匹配最前三个子元素: `:nth-child(-n+3)`
+1. 如何匹配最后三个子元素: `:nth-last-child(-n+3)`
\ No newline at end of file
diff --git a/fe/css/311.md b/fe/css/311.md
index 0e469ef3..3770e2e3 100644
--- a/fe/css/311.md
+++ b/fe/css/311.md
@@ -6,5 +6,18 @@
欢迎在 Issue 中交流与讨论: [Issue 311](https://github.com/shfshanyue/Daily-Question/issues/311)
:::
+::: tip Author
+回答者: [shfshanyue](https://github.com/shfshanyue)
+:::
+
+`css specificity` 即 css 中关于选择器的权重,以下三种类型的选择器依次下降
+
+1. `id` 选择器,如 `#app`
+1. `class`、`attribute` 与 `pseudo-classes` 选择器,如 `.header`、`[type="radio"]` 与 `:hover`
+1. `type` 标签选择器,如 `h1` 和 `p`
+
+其中通配符选择器 `*`,组合选择器 `+ ~ >`,否定伪类选择器 `:not()` 对优先级无影响
+另有内联样式 `` 及 `!important`(最高) 具有更高的权重
+> [`:not` 的优先级影响 - codepen](https://codepen.io/shanyue/pen/dyGQqBe) 可以看出 `:not` 对选择器的优先级无任何影响
\ No newline at end of file
diff --git a/fe/css/342.md b/fe/css/342.md
index 7f8671fa..6ed8417f 100644
--- a/fe/css/342.md
+++ b/fe/css/342.md
@@ -6,5 +6,11 @@
欢迎在 Issue 中交流与讨论: [Issue 342](https://github.com/shfshanyue/Daily-Question/issues/342)
:::
+::: tip Author
+回答者: [shfshanyue](https://github.com/shfshanyue)
+:::
+1. 伪类使用单冒号,而伪元素使用双冒号。如 `:hover` 是伪类,`::before` 是伪元素
+1 伪元素会在文档流生成一个新的元素,并且可以使用 `content` 属性设置内容
+参考
\ No newline at end of file
diff --git a/fe/css/369.md b/fe/css/369.md
new file mode 100644
index 00000000..538acebd
--- /dev/null
+++ b/fe/css/369.md
@@ -0,0 +1,16 @@
+# css 如何匹配前N个子元素及最后N个子元素
+
+
+
+::: tip Issue
+ 欢迎在 Issue 中交流与讨论: [Issue 369](https://github.com/shfshanyue/Daily-Question/issues/369)
+:::
+
+::: tip Author
+回答者: [shfshanyue](https://github.com/shfshanyue)
+:::
+
+见 [【Q307】如何实现表格单双行条纹样式](https://github.com/shfshanyue/Daily-Question/issues/309)
+
++ 如何匹配最前三个子元素: `:nth-child(-n+3)`
++ 如何匹配最后三个子元素: `:nth-last-child(-n+3)`
\ No newline at end of file
diff --git a/fe/css/Readme.md b/fe/css/Readme.md
index 15fba346..2280cd02 100644
--- a/fe/css/Readme.md
+++ b/fe/css/Readme.md
@@ -23,4 +23,5 @@
+ [【Q335】什么是层叠上下文 (stacking contect),谈谈对它的理解](338.html)
+ [【Q336】你用 css 实现过什么不错的效果](339.html)
+ [【Q337】你做前端有多少时间花在写 css 上](340.html)
-+ [【Q339】伪类与伪元素有什么区别](342.html)
\ No newline at end of file
++ [【Q339】伪类与伪元素有什么区别](342.html)
++ [【Q364】css 如何匹配前N个子元素及最后N个子元素](369.html)
\ No newline at end of file
diff --git a/fe/dom/269.md b/fe/dom/269.md
new file mode 100644
index 00000000..6958ca21
--- /dev/null
+++ b/fe/dom/269.md
@@ -0,0 +1,17 @@
+# CSP 是干什么用的了
+
+
+
+::: tip Issue
+ 欢迎在 Issue 中交流与讨论: [Issue 269](https://github.com/shfshanyue/Daily-Question/issues/269)
+:::
+
+::: tip Author
+回答者: [shfshanyue](https://github.com/shfshanyue)
+:::
+
+`CSP` 可以最大限度地防止 `XSS` 攻击,它只允许加载指定的脚本及样式等,通过 http 的响应头 `Content Security Policy` 控制。
+
+如果网站必须加载内联脚本 (inline script) ,则可以提供一个 `nonce` 才能执行脚本,这样攻击者无法注入脚本进行攻击。
+
+可参考阮一峰 [Content Security Policy 入门教程](http://www.ruanyifeng.com/blog/2016/09/csp.html)
\ No newline at end of file
diff --git a/fe/dom/367.md b/fe/dom/367.md
new file mode 100644
index 00000000..e5457156
--- /dev/null
+++ b/fe/dom/367.md
@@ -0,0 +1,10 @@
+# js 动画和 css 动画那个性能比较好
+
+
+
+::: tip Issue
+ 欢迎在 Issue 中交流与讨论: [Issue 367](https://github.com/shfshanyue/Daily-Question/issues/367)
+:::
+
+
+
diff --git a/fe/dom/Readme.md b/fe/dom/Readme.md
index 64c2a606..948a81cc 100644
--- a/fe/dom/Readme.md
+++ b/fe/dom/Readme.md
@@ -3,6 +3,8 @@
+ [【Q161】如何删除一个 cookie](162.html)
+ [【Q210】如何判断当前环境时移动端还是PC端](211.html)
+ [【Q214】input 中监听值的变化是在监听什么事件](215.html)
++ [【Q267】CSP 是干什么用的了](269.html)
+ [【Q284】prefetch 与 preload 的区别是什么](286.html)
+ [【Q311】当 cookie 没有设置 maxage 时,cookie 会存在多久](313.html)
-+ [【Q313】在浏览器中如何监听剪切板中内容](315.html)
\ No newline at end of file
++ [【Q313】在浏览器中如何监听剪切板中内容](315.html)
++ [【Q362】js 动画和 css 动画那个性能比较好](367.html)
\ No newline at end of file
diff --git a/fe/js/149.md b/fe/js/149.md
index 48280bed..bf9101c7 100644
--- a/fe/js/149.md
+++ b/fe/js/149.md
@@ -22,8 +22,22 @@ console.log(JSON.stringify(obj))
回答者: [shfshanyue](https://github.com/shfshanyue)
:::
+> ``` js
+> const obj = {
+> a: 3,
+> b: 4,
+> c: null,
+> d: undefined,
+> get e () {}
+> }
+> ```
+>
+> console.log(JSON.stringify(obj))
+>
+> 输出什么?
+
``` js
{"a":3,"b":4,"c":null}
```
-对重中的 `null`,`function` 将在 `JSON.stringify` 时会忽略掉
\ No newline at end of file
+对其中的 `undefined`,`function` 将在 `JSON.stringify` 时会忽略掉
\ No newline at end of file
diff --git a/fe/js/269.md b/fe/js/269.md
index c7fc9e39..6958ca21 100644
--- a/fe/js/269.md
+++ b/fe/js/269.md
@@ -7,7 +7,11 @@
:::
::: tip Author
-回答者: [DoubleRayWang](https://github.com/DoubleRayWang)
+回答者: [shfshanyue](https://github.com/shfshanyue)
:::
-http://www.ruanyifeng.com/blog/2016/09/csp.html
\ No newline at end of file
+`CSP` 可以最大限度地防止 `XSS` 攻击,它只允许加载指定的脚本及样式等,通过 http 的响应头 `Content Security Policy` 控制。
+
+如果网站必须加载内联脚本 (inline script) ,则可以提供一个 `nonce` 才能执行脚本,这样攻击者无法注入脚本进行攻击。
+
+可参考阮一峰 [Content Security Policy 入门教程](http://www.ruanyifeng.com/blog/2016/09/csp.html)
\ No newline at end of file
diff --git a/fe/js/28.md b/fe/js/28.md
index 35ffeb35..62b59bac 100644
--- a/fe/js/28.md
+++ b/fe/js/28.md
@@ -12,4 +12,63 @@
回答者: [shfshanyue](https://github.com/shfshanyue)
:::
-[fingerprintjs2](https://github.com/Valve/fingerprintjs2)
\ No newline at end of file
+由于不同的系统显卡绘制 `canvas` 时渲染参数、抗锯齿等算法不同,因此绘制成图片数据的 `CRC` 校验也不一样。
+
+``` js
+function getCanvasFp () {
+ const canvas = document.getElementById('canvas')
+ const ctx = canvas.getContext('2d')
+ ctx.font = '14px Arial'
+ ctx.fillStyle = '#ccc'
+ ctx.fillText('hello, shanyue', 2, 2)
+ return canvas.toDataURL('image/jpeg')
+}
+```
+
+因此根据 `canvas` 可以获取浏览器指纹信息。
+
+1. 绘制 `canvas`,获取 `base64` 的 dataurl
+1. 对 dataurl 这个字符串进行 `md5` 摘要计算,得到指纹信息
+
+但是对于常见的需求就有成熟的解决方案,若在生产环境使用,可以使用以下库
+
++ [fingerprintjs2](https://github.com/Valve/fingerprintjs2)
+
+它依据以下信息,获取到浏览器指纹信息,**而这些信息,则成为 `component`**
+
+1. `canvas`
+1. `webgl`
+1. `UserAgent`
+1. `AudioContext`
+1. 对新式 API 的支持程度等
+
+``` js
+requestIdleCallback(function () {
+ Fingerprint2.get((components) => {
+ const values = components.map((component) => component.value)
+ const fp = Fingerprint2.x64hash128(values.join(''), 31)
+ })
+})
+```
+
+在 `fingerprintjs2` 中,对于 `component` 也有分类
+
++ [browser independent component](https://github.com/Valve/fingerprintjs2/wiki/Browser-independent-components):有些 `component` 同一设备跨浏览器也可以得到相同的值,有些独立浏览器,得到不同的值
++ [stable component](https://github.com/Valve/fingerprintjs2/wiki/Stable-components): 有些 `component` 刷新后值就会发生变化,称为不稳定组件
+
+在实际业务中,可根据业务选择合适的组件
+
+``` js
+const options = {
+ excludes: {userAgent: true, language: true}
+}
+```
+
+## 简答
+
+根据 `canvas` 可以获取浏览器指纹信息
+
+1. 绘制 `canvas`,获取 `base64` 的 dataurl
+1. 对 dataurl 这个字符串进行 `md5` 摘要计算,得到指纹信息
+
+若在生产环境使用,可以使用 [fingerprintjs2](https://github.com/Valve/fingerprintjs2),根据业务需求,如单设备是否可跨浏览器,以此选择合适的 `component`
\ No newline at end of file
diff --git a/fe/js/3.md b/fe/js/3.md
index c8beca46..7df2c42b 100644
--- a/fe/js/3.md
+++ b/fe/js/3.md
@@ -7,63 +7,57 @@
:::
::: tip Author
-回答者: [xiaoai7904](https://github.com/xiaoai7904)
+回答者: [shfshanyue](https://github.com/shfshanyue)
:::
-#### 防抖(debounce)
-触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间
-
-##### 示例代码
-```javascript
- // 防抖函数
- function debounce(fn, wait) {
- let timer;
- return function() {
- let _this = this;
- let args = arguments;
- if(timer) { clearTimeout(timer) }
- timer = setTimeout(function(){
- fn.apply(_this, args)
- }, wait);
- }
- }
- // 使用
- window.onresize = debounce(function() {console.log('resize')}, 500)
+## 防抖 (debounce)
+
+防抖,顾名思义,防止抖动,以免把一次事件误认为多次,敲键盘就是一个每天都会接触到的防抖操作。
+
+想要了解一个概念,必先了解概念所应用的场景。在 JS 这个世界中,有哪些防抖的场景呢
+
+1. 登录、发短信等按钮避免用户点击太快,以致于发送了多次请求,需要防抖
+1. 调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多,此时需要一次到位,就用到了防抖
+1. 文本编辑器实时保存,当无任何更改操作一秒后进行保存
+
+代码如下,可以看出来**防抖重在清零 `clearTimeout(timer)`**
+
+``` js
+function debounce (f, wait) {
+ let timer
+ return (...args) => {
+ clearTimeout(timer)
+ timer = setTimeout(() => {
+ f(...args)
+ }, wait)
+ }
+}
```
-#### 节流(throttle)
-高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率
-##### 示例代码
-
-```javascript
- // 方式1: 使用时间戳
- function throttle1(fn, wait) {
- let time = 0;
- return function() {
- let _this = this;
- let args = arguments;
- let now = Date.now()
- if(now - time > wait) {
- fn.apply(_this, args);
- time = now;
- }
- }
- }
- // 方式2: 使用定时器
- function thorttle2(fn, wait) {
- let timer;
- return function () {
- let _this = this;
- let args = arguments;
-
- if(!timer) {
- timer = setTimeout(function(){
- timer = null;
- fn.apply(_this, args)
- }, wait)
- }
- }
- }
+## 节流 (throttle)
+
+节流,顾名思义,控制水的流量。控制事件发生的频率,如控制为1s发生一次,甚至1分钟发生一次。与服务端(server)及网关(gateway)控制的限流 (Rate Limit) 类似。
+
+1. `scroll` 事件,每隔一秒计算一次位置信息等
+1. 浏览器播放事件,每个一秒计算一次进度信息等
+1. input 框实时搜索并发送请求展示下拉列表,没隔一秒发送一次请求 (也可做防抖)
+
+代码如下,可以看出来**节流重在开关锁 `timer=null`**
+
+``` js
+function throttle (f, wait) {
+ let timer
+ return (...args) => {
+ if (timer) { return }
+ timer = setTimeout(() => {
+ f(...args)
+ timer = null
+ }, wait)
+ }
+}
```
-上面`节流`和`防抖`实现方式比较简单,但是已经可以满足日常使用,如果想更近一步了解可以查看[underscore](https://www.bootcss.com/p/underscore/)和[lodash](https://www.lodashjs.com/docs/latest)文档中`debounce`和`thorttle`
\ No newline at end of file
+## 总结 (简要答案)
+
++ 防抖:防止抖动,单位时间内事件触发会被重置,避免事件被误伤触发多次。代码实现重在清零 `clearTimeout`
++ 节流:控制流量,单位时间内事件只能触发一次,如果服务器端的限流即 Rate Limit。代码实现重在开锁关锁 `timer=timeout; timer=null`
\ No newline at end of file
diff --git a/fe/js/361.md b/fe/js/361.md
index c968a53d..ff49ea87 100644
--- a/fe/js/361.md
+++ b/fe/js/361.md
@@ -1,10 +1,55 @@
# js 如何全部替代一个子串为另一个子串
-
+::: tip 更多描述
+ 假设有一个字符串 `hello. hello. hello. ` 需要替换为 `AAA`,即把 `hello. ` 替换为 `A`
+:::
::: tip Issue
欢迎在 Issue 中交流与讨论: [Issue 361](https://github.com/shfshanyue/Daily-Question/issues/361)
:::
+::: tip Author
+回答者: [shfshanyue](https://github.com/shfshanyue)
+:::
+
+如果需要全量替换字符串,可以使用 `String.prototype.replace(re, replacer)`,其中正则表达式需要开启 `global` flag
+
+``` js
+const s = 'foo foo foo'
+s.replce(/foo/g, 'bar')
+```
+
+那如题中,**是否可以使用正则表达式来替代子串**
+
+答:**不可以,因为使用子串构建正则时,有可能有特殊字符,就有可能出现问题**,如下
+
+``` js
+// 期待结果: 'AhelloX hello3 '
+> 'hello. helloX hello3 '.replace(new RegExp('hello. ', 'g'), 'A')
+< "AAA"
+```
+
+而在 `javascript` 中替换子串只能使用一种巧妙的办法:`str.split('foo').join('bar')`
+
+``` js
+> 'hello. hello. hello. '.split('hello. ').join('A')
+< "AAA"
+```
+
+真是一个巧(笨)妙(拙)的办法啊!!!!!**大概 TC39 也意识到了一个问题,于是出了一个新的 API**,在 `ESNext` 中
+
+``` js
+String.prototype.replaceAll()
+
+'aabbcc'.replaceAll('b', '.');
+// 'aa..cc'
+```
+
+详细文档在 [String.prototype.replaceAll](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/replaceAll)
+
+## 总结(及直接答案)
+两种办法
++ `str.split('foo').join('bar')`
++ `str.replaceAll('foo', 'bar')`,在 `ESNext` 中,目前支持性不好
\ No newline at end of file
diff --git "a/fe/\345\211\215\347\253\257\345\267\245\347\250\213\345\214\226/192.md" "b/fe/\345\211\215\347\253\257\345\267\245\347\250\213\345\214\226/192.md"
index 2a37600f..f7143a31 100644
--- "a/fe/\345\211\215\347\253\257\345\267\245\347\250\213\345\214\226/192.md"
+++ "b/fe/\345\211\215\347\253\257\345\267\245\347\250\213\345\214\226/192.md"
@@ -6,5 +6,41 @@
欢迎在 Issue 中交流与讨论: [Issue 192](https://github.com/shfshanyue/Daily-Question/issues/192)
:::
+::: tip Author
+回答者: [grace-shi](https://github.com/grace-shi)
+:::
+
+Open Graph 协议可以让任何一个网页集成到社交图谱中。例如,facebook就是一种社交图谱(social graph)。
+一旦一个网页按照该协议进行集成,这个网页就像是社交图谱的一个节点,例如,你的网页集成了open graph协议,
+按照协议加入了网页的标题,描述以及图片信息等等,那么你在facebook中分享这个网页的时候,facebook就会按照
+你定义的内容来展示这个网页。
+
+这个协议其实很简单,主要是通过在html中加入一些元数据(meta)标签来实现,例如
+在head中加入meta标签,property是以og(open graph)开头, 后面跟着具体属性,content里面是属性的值,
+下面这段描述的就是一个类型为 video.movie,标题为 The rock,以及url和图片信息。这个例子就可以当做是
+为 https://www.imdb.com/title/tt0117500/ 实现了Open Graph协议、
+
+```
+
+
+The Rock (1996)
+
+
+
+
+...
+
+...
+
+```
+结论:
+这个协议主要是Facebook提出来的,为了更好的展示用户分享的网页的内容,实现这个协议,有助于SEO优化,告诉google该网页有哪些内容,以及关键词等。
+可以快速实现Open Graph协议的工具有:
+Wordpress的SEO plugin
+使用Facebook的Facebook Page功能
+
+Reference:
+1. The Open Graph Protocol https://ogp.me/
+2. Open Graph Protocol for Facebook Explained with Examples https://www.optimizesmart.com/how-to-use-open-graph-protocol/
\ No newline at end of file
diff --git a/open/Readme.md b/open/Readme.md
index 9ebf30c6..46f62008 100644
--- a/open/Readme.md
+++ b/open/Readme.md
@@ -15,4 +15,5 @@
+ [【Q225】你相比去年,有哪些成长](open/226.html)
+ [【Q227】你如何看待996](open/228.html)
+ [【Q231】你周末都喜欢做些什么](open/232.html)
-+ [【Q262】当一个排期五天的任务需要在两天后上线如何解决](open/264.html)
\ No newline at end of file
++ [【Q262】当一个排期五天的任务需要在两天后上线如何解决](open/264.html)
++ [【Q337】你做前端有多少时间花在写 css 上](open/340.html)
\ No newline at end of file
diff --git a/open/open/340.md b/open/open/340.md
new file mode 100644
index 00000000..b21981dd
--- /dev/null
+++ b/open/open/340.md
@@ -0,0 +1,10 @@
+# 你做前端有多少时间花在写 css 上
+
+
+
+::: tip Issue
+ 欢迎在 Issue 中交流与讨论: [Issue 340](https://github.com/shfshanyue/Daily-Question/issues/340)
+:::
+
+
+
diff --git a/open/open/Readme.md b/open/open/Readme.md
index 5fabcfda..dc0f9831 100644
--- a/open/open/Readme.md
+++ b/open/open/Readme.md
@@ -15,4 +15,5 @@
+ [【Q225】你相比去年,有哪些成长](226.html)
+ [【Q227】你如何看待996](228.html)
+ [【Q231】你周末都喜欢做些什么](232.html)
-+ [【Q262】当一个排期五天的任务需要在两天后上线如何解决](264.html)
\ No newline at end of file
++ [【Q262】当一个排期五天的任务需要在两天后上线如何解决](264.html)
++ [【Q337】你做前端有多少时间花在写 css 上](340.html)
\ No newline at end of file
diff --git a/server/Readme.md b/server/Readme.md
index cfeedf34..1a96b3e0 100644
--- a/server/Readme.md
+++ b/server/Readme.md
@@ -79,4 +79,6 @@
+ [【Q342】`A, B` 复合索引时,`A=? and B=?` 与 `B=? and A=?` 效果是否一致](db/345.html)
+ [【Q345】postgres 中 Index Scan 与 Index Only Scan 有何区别](db/348.html)
+ [【Q346】Sentry 中 `withScope`,`configureScope` 与 直接 setTags 有何区别](micro-service/349.html)
-+ [【Q350】如何实现一个 timeout 的中间件](micro-service/353.html)
\ No newline at end of file
++ [【Q350】如何实现一个 timeout 的中间件](micro-service/353.html)
++ [【Q358】什么情况下会发送 OPTIONS 请求](server/363.html)
++ [【Q363】如何获取当前系统中的在线用户数 (并发用户数)](server/368.html)
\ No newline at end of file
diff --git a/server/server/288.md b/server/server/288.md
index 1b0de0e3..f1bfb04c 100644
--- a/server/server/288.md
+++ b/server/server/288.md
@@ -10,7 +10,14 @@
回答者: [shfshanyue](https://github.com/shfshanyue)
:::
-如果有 `x-forwarded-for` 的请求头,则取其中的第一个 IP,否则取建立连接 socket 的 remoteAddr
+**如果有 `x-forwarded-for` 的请求头,则取其中的第一个 IP,否则取建立连接 socket 的 remoteAddr。**
+
+而 `x-forwarded-for` 基本已成为了基于 proxy 的标准HTTP头,格式如下,可见第一个 IP 代表其真实的 IP,可以参考 MDN [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For)
+
+``` js
+X-Forwarded-For: 203.0.113.195, 70.41.3.18, 150.172.238.178
+X-Forwarded-For: , ,
+```
以下是 `koa` 获取 IP 的方法
@@ -33,4 +40,6 @@
}
return this[IP];
},
-```
\ No newline at end of file
+```
+
+参见源码:
\ No newline at end of file
diff --git a/server/server/328.md b/server/server/328.md
index 71a9f21e..5d515fb7 100644
--- a/server/server/328.md
+++ b/server/server/328.md
@@ -12,9 +12,9 @@
- `Access-Control-Allow-Origin`
- `Access-Control-Allow-Methods`
-- `Access-Control-Expose-Headers`
- `Access-Control-Allow-Headers`
-- `Access-Control-Max-Age`
- `Access-Control-Allow-Credentials`
+- `Access-Control-Expose-Headers`
+- `Access-Control-Max-Age`
关于如何写一个 `cors` 的中间件可以参考 [koajs/cors](https://github.com/koajs/cors)
\ No newline at end of file
diff --git a/server/server/363.md b/server/server/363.md
new file mode 100644
index 00000000..a794b355
--- /dev/null
+++ b/server/server/363.md
@@ -0,0 +1,16 @@
+# 什么情况下会发送 OPTIONS 请求
+
+
+
+::: tip Issue
+ 欢迎在 Issue 中交流与讨论: [Issue 363](https://github.com/shfshanyue/Daily-Question/issues/363)
+:::
+
+::: tip Author
+回答者: [hedongxiaoshimei](https://github.com/hedongxiaoshimei)
+:::
+
+[搬运地址](https://blog.csdn.net/kahhy/article/details/81563063)
+1:请求的方法不是GET/HEAD/POST
+2:POST请求的Content-Type 异常
+3:请求设置了自定义的header字段
diff --git a/server/server/368.md b/server/server/368.md
new file mode 100644
index 00000000..0e750c2d
--- /dev/null
+++ b/server/server/368.md
@@ -0,0 +1,16 @@
+# 如何获取当前系统中的在线用户数 (并发用户数)
+
+::: tip 更多描述
+ 一些 SaaS 系统基于 Pricing 的考虑,会限制团队人数及同时在线数,如何实现
+:::
+
+::: tip Issue
+ 欢迎在 Issue 中交流与讨论: [Issue 368](https://github.com/shfshanyue/Daily-Question/issues/368)
+:::
+
+::: tip Author
+回答者: [shfshanyue](https://github.com/shfshanyue)
+:::
+
+> 一些 SaaS 系统基于 Pricing 的考虑,会限制团队人数及同时在线数,如何实现
+
diff --git a/server/server/Readme.md b/server/server/Readme.md
index 4a4d70b9..2483eef5 100644
--- a/server/server/Readme.md
+++ b/server/server/Readme.md
@@ -16,4 +16,6 @@
+ [【Q260】如何实现单点登录](262.html)
+ [【Q286】在服务端应用中如何获得客户端 IP](288.html)
+ [【Q325】关于 cors 的响应头有哪些](328.html)
-+ [【Q350】如何实现一个 timeout 的中间件](353.html)
\ No newline at end of file
++ [【Q350】如何实现一个 timeout 的中间件](353.html)
++ [【Q358】什么情况下会发送 OPTIONS 请求](363.html)
++ [【Q363】如何获取当前系统中的在线用户数 (并发用户数)](368.html)
\ No newline at end of file
diff --git a/weekly/Readme.md b/weekly/Readme.md
index 615ffaef..258502c9 100644
--- a/weekly/Readme.md
+++ b/weekly/Readme.md
@@ -265,7 +265,7 @@
+ [【Q264】当 Node 应用发生 gc 时,如何监控](../fe/node/266.html)
+ [【Q265】Node 应用中如何查看 gc 的日志](../fe/node/267.html)
+ [【Q266】bind 与 call/apply 的区别是什么](../fe/js/268.html)
-+ [【Q267】CSP 是干什么用的了](../fe/js/269.html)
++ [【Q267】CSP 是干什么用的了](../fe/dom/269.html)
+ [【Q268】你如何看待 serverless](../fe/前端工程化/270.html)
+ [【Q269】什么是 XSS 攻击,如何避免](../fe/前端工程化/271.html)
+ [【Q270】一张员工表,一个字段代表它的上级,如何查询该员工的所有上级](../server/db/272.html)
@@ -355,4 +355,11 @@
+ [【Q354】在 node 中如何判断一个对象是 stream](../fe/node/357.html)
+ [【Q355】什么是 Iterable 对象,与 Array 有什么区别](../fe/js/358.html)
+ [【Q356】在 node 端如何向服务器上传文件](../base/http/360.html)
-+ [【Q357】js 如何全部替代一个子串为另一个子串](../fe/js/361.html)
\ No newline at end of file
++ [【Q357】js 如何全部替代一个子串为另一个子串](../fe/js/361.html)
++ [【Q358】什么情况下会发送 OPTIONS 请求](../base/http/363.html)
++ [【Q359】CORS 如果需要指定多个域名怎么办](../base/http/364.html)
++ [【Q360】localhost 与 127.0.0.1 有什么区别](../base/network/365.html)
++ [【Q361】既然 cors 配置可以做跨域控制,那可以防止 CSRF 攻击吗 ](../base/http/366.html)
++ [【Q362】js 动画和 css 动画那个性能比较好](../fe/dom/367.html)
++ [【Q363】如何获取当前系统中的在线用户数 (并发用户数)](../server/server/368.html)
++ [【Q364】css 如何匹配前N个子元素及最后N个子元素](../fe/css/369.html)
\ No newline at end of file