chenfei-hnu / Blog

个人整理的跟前端相关的文档 ( This is some front-end development related documentation )
9 stars 2 forks source link

DNS劫持与防治 #37

Open chenfei-hnu opened 4 years ago

chenfei-hnu commented 4 years ago

在部分用户的网络环境中,由于用户设备,中间链路设备被污染或者DNS 服务器被侵入等情况,DNS可能发生被劫持的情况,网络层可以通过设置每种 URL 白名单,匹配请求头,使用TLS 协议,http或者https传输DNS等方式进行规避

对于前端来说,需要关注的是页面CDN域名被劫持,而页面主域名正常,导致页面可以访问,但是资源无法正常加载

解决方案: CDN和主域名都同时承载资源,优先CDN加载,通过window.addEventListener error监听到错误后,根据错误进行资源判断,再通过字符串拼接成相应主域名资源标签,利用document.write重新写入文档加载资源

CDN服务方也可以将相关的检验逻辑写到SDK中,运行时与CDN服务端维护的相关服务进行消息传递以判断及预警

1.如何检测加载错误

1.1 在script或者link加onerror捕捉 在每个script或者link标签中添加onerror属性,捕捉加载错误。

优点:能够准确捕捉资源加载失败的场景,并及时处理 缺点:代码入侵性强,不能够很好的复用。对于利用占位来添加css或者js的方式支持比较困难 可以使用webpack自定义插件添加onerror统一接口

1.2 使用 HTTP HEAD 请求 检测资源是否存在 在html最后加一段js,使用 HEAD 请求对所需要检测的资源进行检测,如果返回404或者503,则触发加载失败重新加载机制

优点:检测代码能够和业务代码很好的分离,能够检测到绝大部分资源加载失败的场景 缺点: 有一定可能造成误判 倘若网络情况比较差且资源加载失败的情况下,延迟比较大

更多信息请看 https://zhuanlan.zhihu.com/p/40682772 1.3 使用window.addEventListener来捕获加载错误,通过捕获,能够在全局捕获到加载错误

window.addEventListener('error', () => {
// to do your things. }, true); 根据文件类型过滤出来css和js即可

优点:准确 缺点:低版本IE浏览器存在兼容性问题,但大部分浏览器支持情况较好

加载失败,则加载原位置之后的所有改域名资源切换到主域名重加载

2.按照依赖顺序准确加载js

1.promise + script src加载 引入promise代码量成本太高,大大增加体积,自己写回调代码量更少 promise加载一个资源的过程中,并不能同时加载另一个资源,加载速慢 function loadJS(url){ return new Promise((resolve,reject)=>{ var script = document.createElement('script'); script.type = 'text/javascript'; script.onload = function(){ resolve(''); }
script.src = url; document.getElementsByTagName('head')[0].appendChild(script); }); } var promises=[]; for(var item of urls){ promises.push(loadJS(item)); } Promise.all(...promises);

2.document.write执行 模拟浏览器加载和执行js的方案,把加载和执行分开,用XmlRequest并行加载资源,然后用eval按依赖顺序执行代码,跨域和错误都需要自己处理

const load = (urls) => {
document.write( urls.map(dep => <script src="${dep}"></script>).join('') ); }; 那么addEventListener则需要放到head里的最开始的地方,在body末尾插入错误处理接口

最终实现方案: window.addEventListener捕获方式来完成检测,document.write来完成加载和执行