AOP(Aspect Oriented Programming):面向切面编程,
它是面向对象基础上发展来的技术,是面向对象更高层次的应用,
它可以在不修改原有代码的情况给组件增强功能。
主流浏览器图片反防盗链方法总结
前言
还记得之前写的那个无聊的插件,前一段时间由于豆瓣读书增加了防盗链策略使得我们无法直接引用他们的图片,使得我这个小插件无法工作。本以为是一个很简单的问题,但是没想到这个小问题硬是让我改了五六遍才改好,可以说是非常的蠢了。总结一下自己犯傻的原因,还是由于自己懒得去深入研究,谷歌百度了问题就直接把方案拿来用了,浅尝辄止人云亦云,解决了表面的问题而没有深入的总结。当然,从另外一个方面讲,我也是初步领会到了前端程序员面对要兼容各种浏览器的需求时头有多大了。
问题
问题很简单,就是我希望在自己的页面里用<img src="xxxx" />
来引用其他网站的一张图片,但是他的网站设置了防盗链的策略,会在后台判断请求的Referrer
属性是不是来自于一个非本域名的网站,如果来源不是本域名就返回403 forbidden
。我的目的就是用最方便的方法使得我的页面能够不受他的防盗链策略的影响。
解决方案
后台预下载
预下载是最直观的一种方法,既然不能直接引用,那我就先后台下载下来,然后将图片链接到下载后的图片即可。这个方法还是比较稳妥的,图片下载下来就是自己的了,不会再受人限制。不过这总有种侵犯知识产权的感觉,而且每张图片都要后台先下载,逻辑处理起来还是有点麻烦的;而且对于那种纯静态页面,没有后台程序供我们发挥,这也就无法实现了。
第三方代理
第三方代理其实算是后台与下载的升级版,其实就是将下载图片的这个过程交给第三方的网站。一个非常好用的代理是images.weserv.nl,我们可以直接将自己需要“盗链”的图片写在请求中即可。我们甚至可以指定一些简单的图片处理参数,让代理帮我们处理。
比如我想盗链https://foo.com/foo.jpg
,并且将图片宽度设置成100,我们就可以直接这样引用:
1 | <img src="https://images.weserv.nl/?url=foo.com/foo.jpg&w=100" /> |
这还是很方便的,不过美中不足的是这个国外的网站在国内的访问速度似乎有点慢,有时候甚至还会被墙,这就有点尴尬了。
删除Header中的Referrer
相比上面两种折腾的方法,如果能直接修改Referrer,那不就省了很多事了么。但是事实上这里的配置还是有挺多坑的,方法也有很多种,一不小心就会跟我一样踩了一遍又一遍。
添加meta标签
一种方法是给页面添加一个meta标签,在meta标签里指定referrer的值,比如<meta name="referrer" content="xxx" />
。网上可以查到各种奇奇怪怪的值,其实我总结了来源于两个地方。
- 一个是来自whatwg的标准。他给meta标签的referrer属性定义了四个值:
never,always,origin,default
。如果需要关闭referrer,就将referrer的值设置成”never”。这个标准还是比较老的,而且在他的主页上也明确写了”This document is obsolete.”。不过据我调研,或许正是由于这个标准比较老,反而导致绝大多数浏览器对他的支持都很好,因祸得福蛤蛤。 - 另外一个是来自MDN的标准。他给meta标签的referrer属性定义了五个值,如果要关闭referrer,就将它的值设置成
no-referrer
。
不过我们需要注意的是,meta标签添加的位置也很重要,有的浏览器能够识别非head标签中的meta标签,有的就不行。在实际使用的时候还要小心,这一点下文会有一个更具体的比较。
添加ReferrerPolicy属性
添加meta标签相当于对文档中的所有链接都取消了referrer,而ReferrerPolicy则更精确的指定了某一个资源的referrer策略。关于这个策略的定义可以参照MDN。比如我想只对某一个图片取消referrer,如下编写即可:
1 | <img src="xxxx.jpg" referrerPolicy="no-referrer" /> |
浏览器支持对比
上面我们讲了两种取消referrer头信息的方法,但其实这却对应了五种写法,而且不同浏览器对这几种写法的支持也是不一样的,我们来看下面的对比表:
- | nothing | meta in head referrer=never | meta in head referrer=no-referrer | meta referrer=never | meta referrer=no-referrer | img referrerPolicy=no-referrer |
---|---|---|---|---|---|---|
Chrome | N | Y | Y | Y | Y | Y |
Firefox | N | Y | Y | N | N | Y |
Edge/IE | N | Y | N | Y | N | N |
可以看出Chrome浏览器对各种写法都支持的最好,棒棒哒;Firefox支持所有标准的写法,但是不支持没有写在head标签中的meta标签;Edge/IE则不支持MDN里定义的”no-referrer”配置项,果然是个古董。。。
总的来说,保证最佳效果的最简单的写法就是添加一个meta标签<meta name="referrer" content="never" />
,这样就不用考虑浏览器的差别了,虽然这种写法并不被官方推荐(主要还是要迁就IE这个古董,放弃了理论上更为正确的标准)。
参考资料
「Spring」JDBC详解
Spring对JDBC做了简化和封装;简化了DAO实现类编写;提供了基于AOP的声明式事务管理;对JDBC中异常做了封装,把原来检查异常封装成了继承自RuntimeException的异常(DataAcessException)。
「Spring」IoC注解实现
关于语义化版本规则(Semver)的领悟
前言
以前一直忽视了版本号规则的重要性,这两天改了一个bug让我深刻的领悟了遵守语义化版本规则(semver)的重要性。尤其是当自己需要造轮子给别人用的时候,如果没有遵循语义化版本规则,是很容易给别人留坑的。。。
简述
首先稍微解释下语义化本本规则,这套规则其实在网上也是到处被搬运(吐槽一波,非常讨厌这种搬运语法啊规则啊这些知识点而不说明出处的行为)。其实这套规则的出处是来自semver的官网。具体的概念文档里解释的很清楚,这里就不赘述了。
问题
问题来源于我对node里ejs的一次错误使用。
ejs包里有一个 renderFile 的方法,这个方法原本是设计成同步的,因此我们可以直接从返回值里获取render之后的结果。
但是最近一次更新,他修改了这个函数的实现,使他支持了异步操作,同时也取消了同步返回结果的功能,导致我在使用的时候出现了没想到的bug。
程序员还是直接看代码比较习惯,直接上一张操作流程图吧:
@asciinema
在2.5.6版本中,他是支持返回值获取结果的,但是在2.5.8中,他突然就取消了这个功能,造成了向下不兼容的情况出现。
当然,引入新功能导致向下不兼容本身并没有错,但是问题就在于新发布的这个版本只是修改了次版本号,根据npm的语义化版本规则,默认的’^2.5.6’版本号会自动升级为’2.x.x’的更新的包。这就导致npm在更新的时候会自动升级到这个向下不兼容的版本,从而使原本可用的代码变得不可用。这样类似的bug相当难以被发现,尤其是当依赖一层套一层之后,谁知道是哪一层引用了这样的包。。。
解决&教训
- 作为包的使用者而言,如果我们不信任某些包以后的版本,我们可以不使用
^
前缀自动更新版本,而是采用确定版本号的方式,这样可以保证即使今后这个包打了坏补丁也不会影响到之前的版本。 - 作为轮子的制造者,在发布一个向下不兼容的版本时,一定要注意修改major version,保证低版本不会因为自动更新导致bug。
- 作为一名普通的码农,也要有一点意识,就是尽量不要使用 ‘undocumented functionality’ 这样的功能很有可能被后续版本淘汰;同时,要学会正确编写异步代码,不能总想着用同步的方式来调用异步api。
嗯,大概就是这些。
参考资料
关于firefox中链接点击弹出空白标签页的问题分析
前言
昨天突然有好心人提醒我说我的网站某些链接在firefox中打开时会弹出 about:blank 的空白页面。本来自己在测试的时候没怎么考虑浏览器的兼容问题,毕竟自己总共也没写几个标签。不过研究了一下发现前端这一行做起来还真挺麻烦的。
问题
原先的代码是这样的,有一个a标签,类似这样:
1 | <a href="javascript:void(0); target="_blank" onclick="somefunction()">haha</a> |
我希望这是一个标签页,为了好看就继承了a标签的样式,而且自己定义了点击事件,不过为了避免链接跳转就在href里用”javascript:void(0);”来阻止页面跳转。
这行简单的代码在chrome里没有问题,不过在 firefox 中如果点击这个标签就会立刻弹出一个 about:blank 的空白标签页,非常的不友好。
解决
这个问题解决起来其实也很简单,原因就在于不知道为什么当时手贱顺手加了个 target="_blank"
,在大多数浏览器会在看到 javascript:void(0);
之后阻止了创建页面的操作,但是firefox却优先考虑创建标签页,这才造成了这个问题。因此解决起来也很简单,把 target="_blank"
删除即可。
思考
但是问题来了,是什么原因导致不同浏览器的执行逻辑不一样呢?
其实我感觉任何一种逻辑的设计都是有他的原理的,查询了一下 mozilla 的文档,我发现了这样的一段话:
Anchor tags are often abused with the onclick event to create pseudo-buttons by setting href to “#” or “javascript:void(0)” to prevent the page from refreshing. These values cause unexpected behavior when copying/dragging links, opening links in a new tabs/windows, bookmarking, and when JavaScript is still downloading, errors out, or is disabled. This also conveys incorrect semantics to assistive technologies (e.g., screen readers). In these cases, it is recommended to use a
<button>
instead. In general you should only use an anchor for navigation using a proper URL.
我们通常会用锚点或者 javascript:void(0);
这个小 trick 来禁止url跳转从而实现我们想要的效果。但是从逻辑上讲,a标签的语义就是链接跳转,我们这种操作其实是违背了a标签的设计初衷的,因此 mozilla 官方并不推荐我们这样做。
比如说,我们认为a标签代表了用户的链接跳转的操作,那么我们就可以相信这肯定对应了一个url,那么我们就可以在浏览器的功能强化中加上一个新功能就是支持用户将这个链接拖动到地址栏以打开新链接。但是我们的这个小trick违背了这样的逻辑链,因此出现问题也就很自然了。
相比之下,button 的语义才是确认用户的意图,这个跟标签页的语义相当,所以他才会推荐我们在做标签页的时候使用button标签。
这些设计也是挺有意思的,然而,尽管我十分认可 mozilla 的解释,但是考虑到页面当前对a标签的样式做的比较好,我也懒得再写button标签的样式,所以最终还是用了a标签。。。
参考资料
「Spring」IoC控制反转
Spring是一个开源的轻量级控制反转(IOC)和面向切面(AOP)的容器框架,它主要是为了解决企业应用开发的复杂性而诞生的,但现在已不止应用于企业服务。
- IOC:Inversion Of Control(控制反转),构成Spring框架的核心基础
各种搜索引擎站长认证失败问题解决
这两天闲着没事就随便找一些奇奇怪怪的搜索引擎,注册了一波站长信息,这时候一般都需要认证站长的所有权,通常有下面几种方法:
- meta 标签认证
- 上传文件认证
- CNAME认证
一般来讲CNAME认证比较稳妥但是要登运营商的管理界面管理,有点麻烦,而且认证之后要是忘了删记录,看起来着实有点凌乱。因此后来我就习惯用认证文件来认证,上传也方便,删除也方便。不过近几次却经常发现这样认证总是失败,本以为是某家平台的问题,但是发现很多家平台都一样。后来研究了一下才发现是因为之前网站开启了https那会,把http的流量全都用301重定向到了https,而一般的认证似乎都是访问的http的页面,导致无法识别重定向后的内容。
解决的方法也很简单,暂时关闭http到https的强制重定向,等认证之后再开启即可(脑子笨,排查半天才发现是这个问题)。