工作中的遇到的一些小知识 7
DNS
DNS作为用来映射域名和IP地址的分布式数据库,使用TCP/UDP端口号53。其中每一级域名限制63个字符,总长度不超过253个字符。
DNS系统中,常见的资源记录类型有:
- A(Address)记录:最重要的记录,用于将特定主机名映射到对应主机的IPv4地址上
- MX记录:用于将特定邮箱地址映射到对应邮箱服务器上
- CNAME(Canonical Name Record)别名记录:用于将某个别名指向某个A记录上
- AAAA记录:和A记录对应,用于将特定主机名映射到对应主机的IPv6地址上
实现上,全球范围近1000台根域名服务器分为13组,编号A到M,剩下的Internet DNS命名空间被委托给其他DNS服务器。DNS系统也有各种各样的DNS软件所支持,其中最普遍的是BIND(Berkeley Internet Name Domain)。在查询时,有两种实现方式:递归和迭代,客户端使用递归,DNS服务器间使用迭代。如查询shenlvmeng.github.io
(忽略本地host和DNS缓存和路由器DNS缓存):
- 客户端发送查询报文
query shenlvmeng.github.io
到边缘DNS服务器(一般是ISP的DNS服务器),DNS先检查缓存,若存在记录则直接返回结果 - 若不存在或记录已过期,则:
- DNS服务器向根域名服务器发送同样的查询报文,根服务器返回顶级域
.io
的权威域名服务器地址 - DNS服务器向
.io
域的权威域名服务器发送查询报文,得到二级域.github.io
的权威域名服务器地址 - DNS服务器向
.github.io
域的权威域名服务器发送查询报文,得到主机shenlvmeng
的A记录,存入自身缓存,设置TTL,返回给客户端
- DNS服务器向根域名服务器发送同样的查询报文,根服务器返回顶级域
最初的DNS域名使用字符仅限于ASCII字符的子集,2008年后,ICANN通过决议,可以使用其他语言作为顶级域名的字符,如“xxx.中国”。使用punnycode码的IDNA系统,可以将unicode字符映射为有效的DNS字符集,有效避免IDN欺骗(即使用长得很像的不同字符作为钓鱼网站)。
域名的所有者和IP也可以通过查找WHOIS域名数据库查询。对于大多数根域名,由ICANN维护,WHOIS的细节由控制那个域的域注册机构维护。
域名污染
指一些刻意制造或无意制造的域名服务器数据包,指向错误的IP地址。这种错误有可能是域名服务器错误工作带来,也有可能是刻意为之。
对于GFW来说,它会对所有经过它的在UDP端口53上的域名查询进行IDS入侵检测,一旦发现与黑名单关键词相匹配的域名查询请求,会伪装成目标域名的解析服务器返回虚假的查询结果。
- 系统默认会从使用ISP提供的域名查询服务器去查询国外的权威服务器时,便被GFW污染,缓存虚假的IP地址。
- 由于TCP连接的机制可靠,理论上无法对TCP协议的域名查询进行污染,理论上可以通过TCP协议查询真实的IP地址。但其实,对于真实的IP地址,会有其他方式封锁,或对查询行为使用连接重置进行拦截
- 通常情况下,设置的NDS服务主要使用海外的DNS服务,所以都需要穿过GFW,不过一些小型的DNS有技术手段回避GFW污染,从而能够访问国外被封锁网站
ISP域名劫持还包含一些互联网提供商劫持部分域名,转到自己制定的网站,已提供自己的广告。
DNS记录
在DNS的分布式数据库中,不同记录类型有不同的用途。下面介绍了一些常见的记录类型。
- A记录,传回一个32位的IPv4地址,映射主机名到IP
- AAAA记录,传回一个128位的IPv6地址,映射主机名到IP
- CNAME:一个主机名的别名,只能指向一个域名,不能指向IP地址,可以保证原域名地址映射IP地址修改时,别名也能同步修改。CNAME意为真实名称,所以应当读作
alias.com
的“CNAME“是real.com
。为保证效率,应当避免CNAME指向其他CNAME。 - DNAME,和CNAME类似,不过不是映射域名,而是把域名下的整个解析子树映射到另一域名。如把
alias.com
DNAME到real.com
后,不影响alias.com
的原有的解析设置。而xxx.alias.com
都会被映射到xxx.real.com
上 - MX(邮件交换)记录,将邮箱后缀(
@
后的部分)映射到类型为A或者AAAA的地址记录,原则上禁止映射到CNAME上 - NS记录,委托DNS区域使用已提供的权威域名服务器
- SRV记录,进行服务定位
所有的记录都有一个有效期(TTL,time-to-live),时间耗尽后,所包含的信息必须从权威服务器上得到更新。
useState
和useEffect
实现思路
这两个React hooks中引入的特性背后是基于闭包 + 数组索引实现的,下面是一个实现的demo。
1 | // useState |
实际使用中,是把useState
、useEffect
这样的hooks放在memorizedState
数组中,共用一个cursor。类似下面这样:
1 | let memoizedState = []; |
其中memorized
数组也是hooks一定要在top level调用的原因。
在React实际实现上,hooks是以链表的形式存储,通过next
属性链接到下一个hook。同时每一个memorized
数组都会绑定到一个fiber上,从而在再次渲染时更新对应节点。让hooks之间互不干扰。
proxy简单了解与应用
Vue 3.0在重构后使用了ES6的proxy新特性来跟踪数据字段的更新。它可以封装一个目标对象,为之添加一个代理,返回一个Proxy对象。
1 | new Proxy(target, handler) |
其中handler
即代理配置对象,也是Proxy对象的“魔力”所在。对于一个空的handler,返回的Proxy近似于target本身。在handler上定义任何handler函数的集合,都会让返回Proxy对象有不同的表现。
handler
有下面一些可选的属性:
apply
监听函数调用的钩子apply: function(target, thisArg, argumentsList) {}
construct
监听使用new
调用的钩子construct: function(target, argumentsList, newTarget) {}
defineProperty
类似Object.defineProperty
defineProperty: function(target, property, descriptor) {}
get
监听属性访问get: function(target, property, receiver) {}
deleteProperty
监听delete
操作deleteProperty: function(target, property) {}
getOwnPropertyDescriptor
监听Object.getOwnPropertyDescriptor
getPrototypeOf()
类似Object.getPrototypeOf
has
监听in
操作has: function(target, prop) {}
isExtensible
监听Object.isExtensible
ownKeys
监听Object.getOwnPropertyNames
和Object.getOwnPropertySymbols
preventExtensions
监听Object.preventExtensions
set
监听属性设置set: function(target, property, value, receiver) {}
setPrototypeOf
类似Object.setPrototypeOf
利用上面的handler
已经可以实现很丰富的功能,immer的produce就有借助proxy来实现。