Referrer策略与防盗链

Referrer策略用于控制浏览器在何种情况下发送referrer信息。该策略可以保护用户的隐私,但也可以使得目前绝大多数站点的防盗链机制失效。

一、介绍
从一个文档发出的请求,以及从文档导航到其他页面,都会有一个Referer头。出于以下原因,我们有时会希望浏览器不发送referer头:
1.隐私
一个社交网站会有每个用户的简介页面,用户会在他们的个人主页中添加一些链接。社交网站可能不希望泄露用户的个人主页URL给被链接的网站(因为个人主页URL可能会泄露其主人的身份信息)。
一些社交网站可能想通知其他网站该链接是从社交网站发起的,但不想泄露包含用户信息的链接(例如,微博中的链接希望告诉对方该链接是在微博中连接过来的,但不希望告诉对方从谁的微博连接过来)。

2.安全
一个网站应用使用https和基于URL的会话标识。应用也许希望链接其他站点的https资源但不想泄露位于URL中的用户会话标识符。
或者,应用可以使用一些url自身的能力(如重置密码的链接、通过链接直接登录账号等)。控制referrer有助于阻止这些有特殊能力的url泄露referrer头。
注意,有其他方式避免这些url的泄露,控制referrer并不足以控制所有的泄露情况。

3.引用
基于HTTPS的博客可能希望连接到一个HTTP上的博客并收到引用链接。

二、referrer策略
Referrer策略包含以下值:

  1. 空字符串
  2. no-referrer
  3. no-referrer-when-downgrade
  4. same-origin
  5. origin
  6. strict-origin
  7. origin-when-cross-origin
  8. strict-origin-when-cross-origin
  9. unsafe-url

下面会详细讲解每种Referrer策略。
1.no-referrer
最简单的策略是“no-referrer”,表示所有的请求都不带referrer。
http://www.lyz810.com/demo/referrer/index.php?referrer=no-referrer

2.no-referrer-when-downgrade
主要针对于受TLS保护的URL(如https),简单的说就是https的页面中,当连接的资源也是https的,则发送完整的referrer,如果连接的资源是http的,就不发送referrer
https://www.lyz810.com/demo/referrer/index.php?referrer=no-referrer-when-downgrade
此例中,音乐可以播放,因为他是http的,不发送referrer,iframe可以显示referrer,因为是https协议。
这个是在没有特别指定referrer策略时,浏览器的默认行为。

3.same-origin
对于同源的链接,会发送referrer,其他的不会。同源意味着域名需要相同,example.com和not.example.com是非同源的。
http://www.lyz810.com/demo/referrer/index.php?referrer=same-origin
上面的例子中可以看到,音乐无法播放了(因为是他站资源),而iframe嵌套的同源页面仍然可以读到referrer。

4.origin
这个策略对于任何资源来说只发送源的信息,不发送完整的url。
http://www.lyz810.com/demo/referrer/index.php?referrer=origin
此例中,音乐无法播放,因为它发送了referrer,iframe中显示的referrer只包含源的信息,不包含完整的url。

5.strict-origin(浏览器可能不支持)
这个策略类似于origin和no-referrer-when-downgrade的合体,如果一个https页面中链接到http的页面或资源,则不会发送referrer。http页面链接以及https链接到https都只发送来源页面的源信息。
https://www.lyz810.com/demo/referrer/index.php?referrer=strict-origin
此例中,音乐正常播放,因为是http的资源,不发送referrer,而iframe中只有源信息。

6.origin-when-cross-origin
该策略在同源的链接中发送完整的URL,其他情况仅发送源信息。相同的域名,http和https协议被认为是非同源的。
http://www.lyz810.com/demo/referrer/index.php?referrer=origin-when-cross-origin
此例中,音乐不能播放,发送源信息,iframe显示完整url。

7.strict-origin-when-cross-origin(浏览器可能不支持)
对于同源请求,发送完整的URL;对于同为https的,只发送源信息;对于http页面只发送源信息;https页面中的http请求不发送referrer。

8.unsafe-url
这个主要是解决https页面中的http资源不发referrer的问题,它会使在https页面中http资源发送完整的referrer。
https://www.lyz810.com/demo/referrer/index.php?referrer=unsafe-url
此例中,音乐不能播放,虽然页面是https,资源是http,但unsafe-url使得浏览器仍发送referrer。

9.空字符串
空字符串表示没有referrer策略,默认为no-referrer-when-downgrade。

三、用法
Referrer策略可以通过以下方法声明:
1.通过http请求头中的Referrer-Policy字段
2.通过meta标签,name为referrer
3.通过<a>、<area>、<img>、<iframe>、<link>元素的referrerpolicy属性。
4.通过<a>、<area><link>元素的rel=noreferrer属性
5.通过隐式继承

四、用法举例
1.http请求头
Referrer-Policy: no-referrer
2.meta标签
<meta name=”referrer” content=”no-referrer” />
3.referrerpolicy属性
<a href=“http://example.com” referrerpolicy=“origin”>
4.rel=noreferrer属性

五、注意事项
Referrer策略还有其他历史遗留的值:
1.never等价于no-referrer
2.default等价于no-referrer-when-downgrade
3.always等价于unsafe-url
4.不建议使用上面三个值,建议使用后面的新值

六、兼容性
IE:不支持(IE高版本中隐式支持default,https页面拉取的http资源不会加referrer)
Edge:仅支持较早版本的值(never、always、origin、default)
Firefox:36+
Chrome:21+
Safari:7.1+(仅支持较早版本的4个值)
Opera:15+
iOS Safari:8+(仅支持较早版本的4个值)

七、关于防盗链
目前大部分网站采用的是判断referrer是否是当前域名或指定白名单域名下的url。而没有referrer的请求都会放行。
referrer策略普及后,单从referrer判断防盗链的方法会失效,所以需要考虑其他的技术手段实现防盗链机制。

CSS.supports API介绍

CSS.supports API用于通过JavaScript检测当前浏览器是否支持某属性及某属性的值。

一、接口用法
1.supports(DOMString property, DOMString value), returns boolean
2.supports(DOMString conditionText), returns boolean

第一种方法接收2个参数,第一个参数是属性的名称(如display、width、margin等);第二个参数是属性的值(如inline-block、100px、-10px等)
第二种方法接收1个参数,为条件字符串,支持or和and运算符,如”(display:inline-block)”、”(width: 100px) or (margin: -10px)”
注意:必须使用括号将每个条件包裹起来,即使只有一个条件

二、规范说明
当supports()方法通过两个参数property和value调用时,如果property是客户端支持的CSS属性名字面量,并且value可以正确的解析为对应属性支持的值,必须返回true。字面量匹配意思是不会对CSS进行处理,前后的空格不会被去除,所以如果有前后空格会导致方法返回false(例如下面的调用会返回false,因为width前面多了一个空格:CSS.supports(‘ width’, ‘100px’))。

当通过单独的一个条件字符串参数进行调用,如果条件字符串能够解析计算为一个支持的属性和值,则返回true;否则返回false。

三、其他说明
1.属性值和属性名不区分大小写
2.如果属性名包含连字符“-”,直接写原始值即可,不需要转换为驼峰方式

四、示例

CSS.supports('width', '-10px');//false,width不能小于0
CSS.supports('height', '50');//false,height需要有单位
CSS.supports('position', 'sticky');//false,也可能为true,测试浏览器不支持sticky
CSS.supports('Z-INDEX', '50');//true,不区分大小写
CSS.supports(' z-index', '50');//false,属性名前面不应该有空格
CSS.supports('z-index', '  50  ');//true,属性值前后可以有空格
CSS.supports('display:none');//false,没有用括号,应为CSS.supports('(display:none)')
CSS.supports('(    display  :  none  )');//true,这种写法前后可以有空格
CSS.supports('(display:none) and (width:-10px)');//false,第二个条件不支持所以整体为false

五、兼容性
IE:不支持
Edge:支持
Firefox:23+
Chrome:28+
Safari:9+
Opera:15+
iOS Safari:9.2+
Android:4.4+

nginx中文文档-ngx_stream_split_clients_module

此页面版本:2016-08-23,57bc4b4b-98b
ngx_stream_split_clients_module模块(1.11.3+)创建用于A/B测试(也叫作分离测试)的变量。

示例配置

stream {
    ...
    split_clients "${remote_addr}AAA" $upstream {
                  0.5%                feature_test1;
                  2.0%                feature_test2;
                  *                   production;
    }

    server {
        ...
        proxy_pass $upstream;
    }
}

split_clients

语法:split_clients string $variable { … }
默认:—
上下文:stream

为A/B测试创建变量,例如:

split_clients "${remote_addr}AAA" $variant {
               0.5%               .one;
               2.0%               .two;
               *                  "";
}

原始字符串的值通过MurmurHash2进行哈希。在给出的示例中,哈希值从0到21474835(0.5%)对应的$variant变量值为“.one”,哈希值从21474836到107374180(2%)对应的值为“.two”,哈希值从107374181到4294967295对应的值为“”(空字符串)。

nginx中文文档-ngx_stream_geoip_module

此页面版本:2016-08-23,57bc4b4b-c73
ngx_stream_geoip_module模块(1.11.3+)创建变量,变量值依赖于客户端的IP地址,使用预编译的MaxMind数据库。

当使用的数据库支持IPv6时,IPv4的地址会被映射为IPv6的地址。
该模块默认不会构建,需要使用–with-stream_geoip_module参数进行编译。
该模块需要MaxMind GeoIP库。

示例配置

stream {
    geoip_country         GeoIP.dat;
    geoip_city            GeoLiteCity.dat;

    map $geoip_city_continent_code $nearest_server {
        default        example.com;
        EU          eu.example.com;
        NA          na.example.com;
        AS          as.example.com;
    }
   ...
}

geoip_country

语法:geoip_country file
默认:—
上下文:stream

指定一个数据库用于决定依赖于客户端IP的国家。下面的变量在使用数据库时可用:
$geoip_country_code
两个字母的国家代码,例如“RU”、“US”

$geoip_country_code3
三个字母的国家代码,例如“RUS”、“USA”

$geoip_country_name
国家名称,例如“Russian Federation”、“United States”

geoip_city

语法:geoip_city file
默认:—
上下文:stream

指定一个数据库用于决定依赖于客户端IP的国家区域以及城市。下面的变量在使用数据库时可用:

$geoip_area_code
电话区号(仅美国)
这个变量可能包含过时的信息,因为相应的数据库字段可能会过时。

$geoip_city_continent_code
两个字母的大陆编码,例如“EU”、“NA”

$geoip_city_country_code
两个字母的国家编码,例如“RU”、“US”

$geoip_city_country_code3
三个字母的国家编码,例如“RUS”、“USA”

$geoip_city_country_name
国家名称,例如“Russian Federation”、“United States”

$geoip_dma_code
美国DMA区域编码(也成为地铁编码),依据Google AdWords API

$geoip_latitude
纬度

$geoip_longitude
经度

$geoip_region
两个标识符的国家行政区代码(行政区、地域、州、省、联邦等),例如“48”、“DC”

$geoip_region_name
国家行政区名称(行政区、地域、州、省、联邦等),例如“Moscow City”、“District of Columbia”

$geoip_city
城市名称,例如“Moscow”、“Washington”

$geoip_postal_code
邮政编码

geoip_org

语法:geoip_org file
默认:—
上下文:stream

指定一个数据库,用于决定依赖于客户端IP地址的组织。下列变量在使用数据库时可用:

$geoip_org
组织名称,例如“The University of Melbourne”

CSS3动画事件

animationstart、animationend以及transitionend分别用于监听css3的关键帧动画的开始、结束以及css3过渡结束事件。

本文Demo:https://www.lyz810.com/demo/cssAnimationEvent/index.html

一、animationstart和animationend事件
animationstart事件在Animation动画开始时触发,对于低版本的webkit内核浏览器使用webkitAnimationStart事件
animationend事件在Animation动画停止时触发,对于低版本的webkit内核浏览器使用webkitAnimationEnd事件
用法示例:

document.querySelector('#test').addEventListener('animationstart', function(){
  console.log('动画开始');
});
document.querySelector('#test').addEventListener('animationend', function(){
  console.log('动画结束');
});

二、animationiteration事件
animationiteration事件会在Animation动画循环播放时触发,主要用于infinite类型的动画,会在每次循环播放完毕时触发。
无限循环的动画会触发animationstart、animationiteration两个事件。
对于低版本的webkit内核浏览器使用webkitAnimationIteration事件。
用法示例:

css:
@keyframes ani{
  from{margin-left: 0;}
  to{margin-left: 300px;}
}
#test{animation:ani 3s infinite;}

js:
document.querySelector('#test').addEventListener('animationiteration', function(){
  console.log('动画播放循环一次');
});

三、transitionend事件
transitionend事件在transition动画结束后触发。
用法示例:

document.querySelector('#test').addEventListener('transitionend', function(){
  console.log('过渡动画完毕');
});

HTML5中input元素的支持类型

目前input元素定义了22种不同的type,它们在不同浏览器中的表现并不一致。本文主要用于在不同设备及浏览器中测试它们的区别。

不同类型的input在不同浏览器中表现的方式有所不同,尤其在移动浏览器中(有些类型会调用不同的键盘类型),下面所有的示例建议在不同的浏览器中测试。

一、文本类型(默认值)-text
这个没有什么好说的,text类型是input的默认类型,当input设置为一个不支持的类型或没有设置类型时,浏览器会将type设置为text

二、电子邮件类型-email
在提交表单时,会验证输入的是否符合电子邮件格式要求,但这个验证比较不准,必要时还需要通过代码进行验证

三、url类型-url
提交表单时会验证是否符合url

四、数字类型-number
只能输入数字,一般浏览器会出现上下三角按钮来控制数值的增减(这个可以通过css控制),也可以直接输入数字。number类型的input支持step属性表示一次增加或减少多少,min为最小值,max为最大值。如果用户手动输入,在输入时是可以突破这些界限的。

五、范围类型-range
在浏览器中多为一个滑杆(类似于调节音量的滑杆),同样支持min、max、step属性。

六、日期类型-date
可以选择年月日。

七、月份类型-month
可以选择年和月。

八、周类型-week
可以选择周和年。

九、时间类型-time
可以选择小时和分钟。

十、日期时间类型-datetime-local
可以选择年月日和时间(本地时间)。

十一、隐藏类型-hidden
不在页面上显示,用于传递一些不需要用户输入的值。

十二、搜索类型-search
这个与普通的text并没有什么区别。

十三、颜色类型-color
用于选取颜色,会调出调色板。

十四、电话类型-tel
用于输入电话号码,一般移动浏览器会自动调用数字键盘。

十五、密码类型-password
用于输入密码,显示为实心圆点或星号等。

十六、复选框-checkbox
可以同时选择多个值,可以通过点击取消。

十七、单选框-radio
只能选择一个值,再次单击也不能取消,只能通过单击相同name的其他radio来取消当前的radio。

十八、文件类型-file
用于选择文件。

十九、表单提交-submit
用于提交表单,与button外观一致。

二十、图片类型-image
在表单中显示图片。

二十一、重置类型-reset
重置表单的所有内容。

二十二、按钮类型-button
一个单纯的按钮,没有默认的事件。

nginx中文文档-ngx_stream_geo_module

此页面版本:2016-08-10,57ab4631-be8
ngx_stream_geo_module模块(1.11.3+)根据客户端IP地址创建变量。

示例配置:

geo $geo {
    default        0;

    127.0.0.1      2;
    192.168.1.0/24 1;
    10.1.0.0/16    1;

    ::1            2;
    2001:0db8::/32 1;
}

geo

语法:geo [$address] $variable { … }
默认:—
上下文:stream

描述指定变量的值与客户端IP地址之间的依赖关系。默认情况下,地址从$remote_addr变量中获取,但是它可以从另外的变量中获取,例如:

geo $arg_remote_addr $geo {
    ...;
}

由于变量在使用时才会解析,可以在geo中声明一个很大的变量映射表,不会引起任何额外的开销。
如果变量的值不是一个合法的IP地址,则使用“255.255.255.255”。
地址可以指定为CIDR地址块格式,也可以为范围。
下面特殊的参数同样受支持:
delete
删除指定的网络。

default
为那些没有匹配任何指定IP地址的客户端地址设置一个默认值。当地址是以CIDR方式指定,“0.0.0.0/0”和“::/0”用于替换默认值。当默认值没有指定,则默认值为空字符串。

include
包含一个含有地址和值的文件。可以有多个包含。

ranges
声明地址定义为一个范围。这个参数应该在最先出现。为了加快载入的速度,地址应该以升序排列。

例子:

geo $country {
    default        ZZ;
    include        conf/geo.conf;
    delete         127.0.0.0/16;

    127.0.0.0/24   US;
    127.0.0.1/32   RU;
    10.1.0.0/16    RU;
    192.168.1.0/24 UK;
}

conf/geo.conf文件包含以下内容:

10.2.0.0/16    RU;
192.168.2.0/24 RU;

最匹配的值将被使用。例如,地址127.0.0.1会使用“RU”,而不是“US”。

带范围的例子:

geo $country {
    ranges;
    default                   ZZ;
    127.0.0.0-127.0.0.0       US;
    127.0.0.1-127.0.0.1       RU;
    127.0.0.1-127.0.0.255     US;
    10.1.0.0-10.1.255.255     RU;
    192.168.1.0-192.168.1.255 UK;
}

JavaScript Vibration震动API

Vibration API用于控制移动端设备的震动器,它可以设置一个震动序列以完成不同时间间隔的震动频率。

一、应用场景

震动API主要应用于移动端游戏等交互类页面,例如设计类游戏可以在击中目标后调用震动器来增强用户体验。
它还可以用来做报错类的提醒,例如用户对一个表单的必填项没有进行填写,在校验失败后,可以调用震动API来提示用户进行填写。
具体使用场景需要考虑清楚,以免滥用反而影响用户体验。

二、兼容性

目前在caniuse上看到的兼容性情况是有问题的,有些浏览器虽然兼容,但基本上除了移动设备外,其他的上网设备都没有震动器,所以桌面版的浏览器虽然支持此API,但并不能使用(使用没有效果但不报错),故只应该应用于移动项目中。
目前在以下APP(Android系统)的最新版本中测试均有效:
360极速浏览器
UC浏览器
手机QQ内置浏览器(未测试QQ浏览器,但应该会支持)
微信
微博
三星手机默认浏览器(Android 5.1.1版本)

三、用法

navigator.vibrate可以控制震动器震动
它接收一个参数,表示震动序列,例如:
navigator.vibrate(1000)表示震动1000毫秒
navigator.vibrate(1000, 500, 1000)表示震动1000毫秒后,暂停500毫秒,然后再震动1000毫秒
当在一个震动的过程中,希望取消震动,则可以调用此方法,第一个参数为null或[]、[0]等:
navigator.vibrate(0)
navigator.vibrate(null)
navigator.vibrate([])
navigator.vibrate([0])
navigator.vibrate([0, 0, 0, ……])//全都是0,没什么意义

四、演示
请使用手机打开,支持微信,建议WIFI环境下打开,需要消耗600k左右的流量。
https://www.lyz810.com/demo/vibration/

JavaScript在线状态检测API

在线状态检测API用于检测当前的网络是否正常,包括是否在线以及在线状态改变事件。

一、当前在线状态属性

navigator.onLine用于检测当前的网络状态,为布尔型,用户网络连通则值为ture,否则值为false

二、状态改变事件

为window绑定online及offline事件可以监听网络连通性的改变:

window.addEventListener('online', function(){alert('网络已连接')},false);
window.addEventListener('offline', function(){alert('网络已断开')},false);

注意:IE8中需要给document.body绑定事件而不是window
此处网络连通性的变化指的是物理上的连通性变化,如果是在控制台将网络限制为offline则不会触发相应的事件。

三、兼容性

IE:8+
Chrome:14+
Firefox:3.5+(4-40存在bug,只有在offline模式下才会显示正确,否则onLine的值一直是true)
Safari:5+