Javascript类型转换-ToNumber

转换规则:
Undefined->NaN
Null->+0
Boolean->true转为1,false转为-0
Number->返回入参(不转换)
Symbol->抛出TypeError异常

Object转换Number规则:
1. 通过ToPrimitive(argument, hint Number)将Object转为原始值primValue
2. 返回ToNumber(primValue)
ToPrimitive参见https://blog.lyz810.com/article/2016/12/javascript-primitive-value/

示例1:


Number({
  valueOf() {
    return true;
  },
  toString() {
    return false;
  }
});//返回1

解释:
根据ToPrimitive规则,当前对象没有定义@@toPrimitive方法,则使用默认的转换规则,此处要转Number,所以先尝试调用valueOf,再尝试调用toString
该对象中定义了valueOf,且valueOf返回的不是一个Object,则ToPrimitive返回的值为true
这时再调用一次ToNumber,可以得出true转为Number结果为1

示例2:


Number({
  [Symbol.toPrimitive]() {
    return null;
  },
  toString() {
    return true;
  },
  valueOf() {
    return 2;
  }
});//返回0

解释:
这里虽然有了ValueOf和toString但定义了Symbol.toPrimitive,属于自定义了转原始值的方法,所以原始值转换结果为null
根据文章开头的规则,null转Number结果是0

字符串转数字规则:
首先ToNumber需要将字符串按照下面的语法进行解析,如果不能解释为字符串数字字面量(StringNumericLiteral),则结果为NaN
语法:
下面可选代表有0个~任意多个
字符串数字字面量StringNumericLiteral(2种):
1. 可选空白串(StrWhiteSpace
2. 可选空白串(StrWhiteSpaceStrNumericLiteral 可选空白串(StrWhiteSpace

空白串StrWhiteSpace
空白字符(StrWhiteSpaceChar)可选空白串(StrWhiteSpace

空白字符StrWhiteSpaceChar(2种):
1. 空白(TAB:U+0009、VT:U+000B、FF:U+000C、SP:U+0020、NBSP:U+00A0、ZWNBSP:U+FEFF、USP)
2. 行结束符(LF:U+000A、CR:U+000D、LS:U+2028、PS:U+2029)

StrNumericLiteral(4种,十进制,二进制,八进制,十六进制):
1. StrDecimalLiteral
2. BinaryIntegerLiteral(0b或0B开头,正则表示为/^0b[01]+$/i)
3. OctalIntegerLiteral(0o或0O开头,正则表示为/^0o[0-7]+$/i)
4. HexIntegerLiteral(0x或0X开头,正则表示为/^0x[\da-f]+$/i)

StrDecimalLiteral(3种,不带符号,正号,符号):
1. StrUnsignedDecimalLiteral
2. +StrUnsignedDecimalLiteral
3. -StrUnsignedDecimalLiteral

StrUnsignedDecimalLiteral(4种)
1. Infinity 无穷
2. DecimalDigits . [DecimalDigits] [ExponentPart](例子:1.、1.1、1.1e1、 1.1E1,注意e或E后面必须是整数)
3. .DecimalDigits [ExponentPart](例子:.1、.1e1、.1E1)
4. DecimalDigits [ExponentPart](例子:1、1e1、1E1)

字符串数字字面量和数字字面量有几处不同:
1. 前者允许在字符串开头及结尾添加一些空白或换行符
2. 前者表示十进制时,前面可以有任意多个前导0,而后者前导0代表8进制(读者可以尝试运行Number(‘012’) === 012)
3. 前者可以添加+-号声明他的符号位
4. 前者在空或只包含空白字符的时候,转换结果为+0
5. Infinity和-Infinity被看做是字符串数字字面量而不是数字字面量

示例:


Number(''); // 0 空字符串
Number(' '); // 0 空白字符
Number('\n'); // 0 行分隔符系列
Number('\ufeff');// 0,空白字符系列
Number(' 123 '); // 123,前后允许有空白
Number('012'); // 12,前导0不代表8进制,就是10进制
Number('0000012'); // 12,可以多个前导0
Number('0b11'); // 3,二进制
Number('0x0a'); // 10,十六进制
Number('100g'); // NaN,注意与parseInt区别
Number('Infinity'); // Infinity
Number('2e2'); // 200

Javascript 类型转换-ToBoolean

转换规则:
Undefined->false
Null->false
Boolean->返回参数值
Number->当参数为+0、-0或NaN时返回false,其他情况返回true
String->当参数为空字符串时(字符串长度为0),返回false,其他情况返回true
Symbol->true
Object->true

Argument Type Result
Undefined Return false.
Null Return false.
Boolean Return argument.
Number If argument is +0, -0, or NaN, return false; otherwise return true.
String If argument is the empty String (its length is zero), return false; otherwise return true.
Symbol Return true.
Object Return true.

Javascript原始值

JavaScript原始值是类型转换中的一个重要的概念,涉及到对象的类型转换时,会先转成原始值再进行其他转换。

建议先看最后面的例子,尝试在浏览器里运行后,再详细阅读原理

一、ToPrimitive ( input [ , PreferredType ] )
转原始值方法:

  1. 确保input是一个JavaScript的合法值
  2. 如果input不是一个Object类型的值返回input本身,否则继续
  3. 如果PreferredType没有传,则令hint为“default”,跳到步骤6
  4. 如果PreferredType是字符串,则令hint为“string”,跳到步骤6
  5. 如果PreferredType是数字,则令hint为“number”
  6. 令exoticToPrim为GetMethod(input, @@toPrimitive)返回值,其中@@toPrimitive是一个用于将对象转成原始值的方法,见后面的例子
  7. 如果exoticToPrim为undefined,继续步骤8,否则跳到步骤10
  8. 如果hint为“default”则将其改为“number”
  9. 返回OrdinaryToPrimitive(input, hint)的值,结束
  10. 令result为Call(exoticToPrim, input, « hint »)的返回值
  11. 如果result的类型不是Object,则返回result,结束流程,否则抛出TypeError异常

二、IsPropertyKey ( argument )
如果入参是字符串或Symbol类型,返回true,否则返回false

三、GetMethod ( V, P )

  1. 确保IsPropertyKey(P)是true
  2. 令func为GetV(V, P)的返回值
  3. 如果func为null或undefined,返回undefined,结束
  4. 如果func是一个可以被调用的方法,返回func,否则抛出一个TypeError异常

四、GetV ( V, P )
GetV用来得到属性的值,如果该值不是对象,则使用适合于该值类型的包装器对象来执行属性查找。 使用参数V和P调用操作,其中V是值,P是属性键。
第一部分中通过GetMethod(input, @@toPrimitive)调用GetV实际就是看input的@@toPrimitive是不是一个可以调用的方法,如果是,就返回这个方法,否则抛出异常

五、OrdinaryToPrimitive ( O, hint )

  1. 确保O是一个Object,hint是一个字符串,且只能是“string”或“number”
  2. 如果hint是“string”,令methodNames为[“toString”,”valueOf”](是一个有序的list),否则就是[“valueOf”,”toString”](顺序返回来)
  3. 遍历methodNames,并看每一项是不是可调用的方法,如果是则调用这个方法,然后看返回值,如果返回值不是个Object,OrdinaryToPrimitive函数直接返回这个返回值
  4. 如果上面遍历都没有符合条件,则抛出TypeError异常

六、示例
下面以Object转Number为例,观察如何调用初始值转换
1. 已知Object转Number的步骤如下:
令primValue为ToPrimitive(argument, hint Number)返回值
返回ToNumber(primValue)
2. +{}会将Object转为Number类型
来看第一段代码

const test1 = {
  valueOf: () => 2,
  toString: () => 3
};
console.log(+test1);

以上代码打印结果为2,转换过程如下:
1. 待转换的为Object(第一部分中的input),待转换类型为Number
2. 取test1的@@toPrimitive方法,这里没有,则要调用OrdinaryToPrimitive
3. 由于这里第二个参数为number,所以按顺序调用test1的valueOf和toString方法
4. 先调用valueOf,首先valueOf是一个函数,可以被调用,且返回值不是一个Object类型(这里返回值是2,是Number类型),那么OrdinaryToPrimitive返回的就是2
5. 再次调用ToNumber(2)最终结果还是2

如果没有valueOf:

const test2 = {
  toString: () => 3
};
console.log(+test2);

打印toString返回的值3

如果valueOf不是个方法,或者valueOf返回值是个Object:

const test3 = {
  valueOf: 2,
  toString: () => 3
};
console.log(+test3);

const test4 = {
  valueOf: () => ({}),
  toString: () => 3
};
console.log(+test4);

均打印toString的返回值3

valueOf返回值为非Object类型的其他值

const test5 = {
  valueOf: () => '0xa',
  toString: () => 3
};
console.log(+test5);

const test6 = {
  valueOf: () => 'a',
  toString: () => 3
};
console.log(+test6);

const test7 = {
  valueOf: () => null,
  toString: () => 3
};
console.log(+test7);

分别打印10,NaN,0
首先三个例子中均返回了valueOf的值作为原始值,根据ToNumber的规则,对原始值再进行一次ToNumber
也就是分别对’0xa’,’a’,null进行了一次转换,等同于+’0xa’,+’a’,+null

如果valueOf和toString返回值都是Object

const test8 = {
  valueOf: () => ({}),
  toString: () => ({})
};
console.log(+test8);

那么根据上面的算法,应该抛出TypeError异常,Chrome控制台运行结果为Uncaught TypeError: Cannot convert object to primitive value,符合预期

上面的例子都没有@@toPrimitive方法,我们看看@@toPrimitive方法如何使用:

const test9 = {
  [Symbol.toPrimitive]: (hint) => {
    console.log(hint);
    return 2;
  }
};
console.log(+test9);

结果输出number和2,由于这里只演示转数字,所以hint就是“number”,实际可以根据不同的类型返回不同的值,例如:

const test10 = {
  [Symbol.toPrimitive]: (hint) => {
    switch (hint) {
      case 'number':
        return 2;
      case 'string': 
        return 'Hello world';
      default: 
        throw new TypeError('转换不了')
    }
  }
};
console.log(+test10, `${test10}`);

以上返回的是2和Hello world

七、应用
一个简易的Money对象,转为数字时,返回数字金额,当转为字符串时自动添加人民币¥前缀

const moneyIn = {
  value: 10,
  [Symbol.toPrimitive](hint) {
    switch (hint) {
      case 'number':
        return this.value;
      case 'string': 
        return `¥${this.value}`;
      default: 
        throw new TypeError('出错了');
    }
  }
}
const moneyOut = {
  value: 5,
  [Symbol.toPrimitive](hint) {
    switch (hint) {
      case 'number':
        return this.value;
      case 'string': 
        return `¥${this.value}`;
      default: 
        throw new TypeError('出错了');
    }
  }
}
console.log(`收入:${moneyIn},支出:${moneyOut},余额¥${moneyIn - moneyOut}`);

注意这里只能相减,根据隐式类型转换规则,两个对象相减,会先将对象转为Number,而相加则并非如此,具体转换规则会在后续文章中分析讲解

HTTP状态码详解之101

参考RFC2616,10.1.2节

服务器理解并愿意服从客户端含有Upgrade信息头字段的请求,以改变当前连接使用的应用层协议。
服务器在响应101状态码的最后空行后,将立即切换到响应头中定义的Upgrade字段的协议。

协议只有在对其有益的前提下才应该切换。例如,切换到一个新的HTTP版本比用老版本更有益,切换到一个实时的、同步的协议在使用这些特性传送资源会更优越。

HTTP状态码详解之100

参考RFC2616,10.1.1节和8.2.3节

一、1xx类的状态码
1xx的状态码表示一个临时的响应,仅由状态行和可选头构成,由空行结尾。对该类状态码,不需要头部。由于HTTP1.0没有定义任何1xx系列的状态码,所以服务器禁止向HTTP1.0的客户端响应1xx状态码,除非出于实验目的。
客户端必须准备好在正常响应前接收1个或多个1xx状态的响应,即使客户端没有期望一个100(continue)状态码信息。非预期的1xx状态码响应可以被忽略。
代理必须转发1xx响应,除非代理和客户端之间的连接关闭或代理本身的请求导致了1xx的响应(例如,如果代理添加“Expect: 100-continue”在请求头域中,那么它就不该转发对应的100响应)。

二、100(Continue)状态码
客户端应该继续它的请求。这个过渡的响应用于告知客户端,请求的初始部分已经被服务器收到,并且没有被服务器拒绝。客户端应该继续发送剩余的请求,如果请求已经完成,就忽略这个响应。服务器必须在请求完成后发送一个最终的响应。
100状态码的用途主要是,允许客户端发送带请求体的请求前,判断服务器是否愿意接收请求(通过请求头)。在某些情况下,如果服务器在不看请求体就拒绝请求时,客户端就发送请求体是不恰当的或低效的。

对HTTP1.1的客户端的要求:
如果客户端将在发送请求体之前等待100状态码的响应,则它必须发送一个Expect请求头,值为“100-continue”。
如果客户端不打算发送请求体,就禁止发送值为“100-continue”的Expect请求头。

由于早起实现的原因,协议允许一些有歧义的情况,例如客户端可以发送“Expect: 100-continue”而不接收417或100状态码。所以,客户端发送这个头部时,不应该无限期的等待100状态码返回而不发送请求体。

对HTTP1.1的服务器的要求:
当接收到包含Expect的值为“100-continue”的请求头时,服务器必须响应100状态码并继续读取输入流,或者响应一个最终的状态码。服务器禁止在发送100状态码响应前等待请求体。如果返回了一个最终的状态码,它可以终止传输连接或者可以继续读剩余的请求并丢弃,但禁止处理请求。
如果客户端使用HTTP1.0或更低版本的协议或者没有在请求头中发送Expect信息,则服务器不应该发送100状态码响应。但有个例外:为了兼容RFC2068,服务器可以发送100状态码响应给HTTP1.1的PUT或POST请求,即使它们不包含Expect请求头。这个例外只对HTTP1.1的请求有效,不包括其他任何版本。
服务器可以在已经接到部分或全部请求体后,不发送100状态码的响应。
发送100状态码响应的服务器必须在收到并处理请求体后,发送一个最终响应码,除非连接过早的中断。
如果服务器收到了一个不包含请求头Expect的值为“100-continue”的请求,且请求包含请求体,并且服务器在读取完整请求前响应了最终状态码,则服务器在读取全部请求前不应该关闭传输连接。否则,客户端可能不能可靠的接收响应的信息。但该需求不会限制服务器保护自身受到攻击或接到一些非法的恶意客户端请求。

对于HTTP1.1代理的要求:
如果代理包含一个Expect值为“100-continue”的请求头的请求,并且它知道下一跳的服务器支持HTTP1.1及更高版本的协议,或者不知道下一跳服务器的HTTP版本,它就必须转发请求包含Expect头域。
如果代理知道下一跳服务器是HTTP1.0以及更低版本,它就禁止转发这个请求,并必须返回一个417状态码。
代理应该维护一个最近联系的下一跳服务器的HTTP版本缓存记录。
代理禁止向一个来自HTTP1.0或更早版本的客户端且不包含Expect值为“100-continue”的请求转发100状态码响应。这个要求会覆盖转发1xx响应的总体规则。

Nginx源码安装自动升级脚本

一个自动升级源码安装的nginx的脚本

脚本可以获取当前nginx版本、官网最新版本
如果有更新,则会自动下载、解压,并根据当前的配置进行编译,安装
最后会重启nginx,并删除下载的文件


#!/bin/bash
nginx=/usr/sbin/nginx;
localVersion=`nginx -v 2>&1 | cut -c22-`
serverVersion=`curl https://nginx.org/en/CHANGES > .nginxupdate 2>/dev/null && sed -n 2p .nginxupdate | cut -d' ' -f4`
echo 当前安装版本为:$localVersion,最新版本为$serverVersion
rm -rf .nginxupdate
if [ "$localVersion" = "$serverVersion" ]; then
echo 当前已是最新版本
exit 0
fi
echo 正在下载最新版本$serverVersion
wget https://nginx.org/download/nginx-$serverVersion.tar.gz && tar -xzvf nginx-$serverVersion.tar.gz
cd nginx-$serverVersion
./configure `nginx -V 2>&1 | sed -n 5p | cut -d':' -f2-`
make && make install
$nginx -s stop && $nginx
cd ..
rm -rf nginx-$serverVersion.tar.gz
rm -rf nginx-$serverVersion
echo 升级完毕
$nginx -V

文件下载响应头设置

本文对比了下载文件头几种不同设置方式的兼容性,并提供了测试方法。

如果想让一个文件调用浏览器下载功能进行下载,而不是直接在浏览器中打开,则需要设置响应头的Content-Disposition字段。
下载响应头的设置在不同浏览器中的兼容性各不一样,下面将探索各个浏览器之间的不同,以及找出一种可以兼容各大主流浏览器的方案。
测试环境说明(可根据兼容性要求自行测试):
Chrome 57,系统版本MacOS 10.12.3
Safari 10.0.3,系统版本MacOS 10.12.3
Firefox 52,系统版本Windows 2003
Edge 14,系统版本Windows 10
IE 11,系统版本Windows Server 2008
IE10,系统版本Windows Server 2008
IE9,系统版本Windows Server 2008

服务端代码如下:

$fnType = $_GET['fntype'];
if ($fnType == 'ascii') {
	$filename = 'English Filename.txt';
} else {
	$filename = '中文文件名.txt';
}
$urlencode = isset($_GET['urlencode']);
if ($urlencode) {
	$filename = rawurlencode($filename);
}
$outputType = isset($_GET['output']) ? $_GET['output'] : null;
if ($outputType == 'old') {
	header("Content-Disposition: attachment; filename=$filename");
} else if ($outputType == 'new') {
	header("Content-Disposition: attachment; filename*=UTF8''$filename");
} else {
	header("Content-Disposition: attachment; filename=$filename; filename*=UTF8''$filename");
}
if (isset($_GET['withcontenttype'])) {
	header('Content-Type: text/plain');
} else {
	header('Content-Type: ');
}

查看响应头方法:
curl -I url

一、纯ASCII字符文件名兼容性
测试地址:https://demo.lyz810.com/downloadHeader/?fntype=ascii&output=old
响应头:
Content-Disposition: attachment; filename=English Filename.txt
结果:
Chrome:English Filename.txt
Safari:English Filename.txt
Firefox:English(由于文件名含有空格,空格后面的字符都被Firefox忽略了)
Edge:English Filename.txt
IE 11:English Filename.txt
IE10:English Filename.txt
IE9:English Filename.txt

二、纯ASCII字符文件名url编码
测试地址:https://demo.lyz810.com/downloadHeader/?fntype=ascii&output=old&urlencode=1
响应头:
Content-Disposition: attachment; filename=English%20Filename.txt
结果:
Chrome:English Filename.txt
Safari:English%20Filename.txt
Firefox:English%20Filename.txt(由于文件名含有空格,空格后面的字符都被Firefox忽略了)
Edge:English Filename.txt
IE 11:English Filename.txt
IE 10:English Filename.txt
IE 9:English Filename.txt

三、中文文件名,utf-8不进行url编码
测试地址:https://demo.lyz810.com/downloadHeader/?output=old
响应头:
Content-Disposition: attachment; filename=中文文件名.txt
结果:
Chrome:中文文件名.txt
Safari:中文文件名.txt
Firefox:中文文件名.txt
Edge:涓枃鏂囦欢鍚_txt.txt
IE 11:涓枃鏂囦欢鍚_txt
IE 10:downloadHeader(url的pathname部分)
IE 9:涓枃鏂囦欢鍚_txt

四、中文文件名,utf-8进行url编码
测试地址:https://demo.lyz810.com/downloadHeader/?output=old&urlencode=1
响应头:
Content-Disposition: attachment; filename=%E4%B8%AD%E6%96%87%E6%96%87%E4%BB%B6%E5%90%8D.txt
结果:
Chrome:中文文件名.txt
Safari:%E4%B8%AD%E6%96%87%E6%96%87%E4%BB%B6%E5%90%8D.txt
Firefox:%E4%B8%AD%E6%96%87%E6%96%87%E4%BB%B6%E5%90%8D.txt
Edge:中文文件名.txt
IE 11:中文文件名.txt
IE 10:中文文件名.txt
IE 9:中文文件名.txt

五、中文文件名,使用filename*并进行url编码
测试地址:https://demo.lyz810.com/downloadHeader/?output=new&urlencode=1
响应头:
Content-Disposition: attachment; filename*=UTF8”%E4%B8%AD%E6%96%87%E6%96%87%E4%BB%B6%E5%90%8D.txt
结果:
Chrome:中文文件名.txt
Safari:downloadHeader.txt
Firefox:中文文件名.txt
Edge:downloadHeader
IE 11:downloadHeader
IE 10:downloadHeader
IE 9:downloadHeader

六、中文文件名,同时使用filname*和filename,并进行url编码
测试地址:https://demo.lyz810.com/downloadHeader/?urlencode=1
响应头:
Content-Disposition: attachment; filename=%E4%B8%AD%E6%96%87%E6%96%87%E4%BB%B6%E5%90%8D.txt; filename*=UTF8”%E4%B8%AD%E6%96%87%E6%96%87%E4%BB%B6%E5%90%8D.txt
结果:
Chrome:中文文件名.txt
Safari:%E4%B8%AD%E6%96%87%E6%96%87%E4%BB%B6%E5%90%8D.txt
Firefox:中文文件名.txt
Edge:downloadHeader
IE 11:downloadHeader
IE 10:downloadHeader
IE 9:downloadHeader

七、结论
1.IE系列(包括Edge)对于中文,只支持urlencode的方式,不能识别filename*
2.Firefox支持不编码的中文和filename*
3.Chrome支持各种上面测试的各种类型
4.Safari仅支持ISO格式的中文,此文中并未给出测试实例,请参考http://lgbolgger.iteye.com/blog/2108396

使用OpenSSL为Nginx签发自签名证书

本文介绍使用openssl命令为nginx生成自签名的证书。注:仅用于本地测试使用,自签名证书不被浏览器认可,不能应用于生产环境。

一、生成RSA私钥
openssl genrsa -out local.lyz810.com.key 2048
上述命令在当前目录下使用RSA2048算法生成一个文件名为local.lyz810.com.key的pem格式的私钥。

二、使用生成好的私钥签发证书
openssl req -new -x509 -days 3650 -key local.lyz810.com.key -out lyz810.com.crt
输入命令后,会提示输入一些信息,由于是测试使用,可以任意填写。
配置好后添加到nginx上,浏览器打开会提示证书错误,选择继续访问即可。

三、openssl genrsa用法说明
genrsa的语法如下:

openssl genrsa [-help] [-out filename] [-passout arg] [-aes128] [-aes192] [-aes256] [-camellia128] [-camellia192] [-camellia256] [-des] [-des3] [-idea] [-f4] [-3] [-rand file(s)] [-engine id] [numbits]

参数详解:
-help:打印帮助信息
-out filename:生成文件的名称
-passout arg:生成的文件的短语密码源
-aes128|-aes192|-aes256|-camellia128|-camellia192|-camellia256|-des|-des3|-idea:这些选项会在输出私钥文件前使用该参数的加密算法将私钥加密。如果没有这些参数中的一个,则生成的私钥没有密码保护。如果没有通过passout指定短语密码,则会提示输入短语密码用于加密。
-F4|-3:使用的公开指数,值为65537或3,默认为65537
-rand files(s):一个或多个包含用于随机数发生器播种的随机数据的文件或EGD socket。多个文件之间的分隔符根据系统不同而不同,Windows中是分号“;”,OpenVMS中是逗号“,”,其他系统中是冒号“:”。
-engine id:通过唯一的id指定一个引擎。
-numbits:私钥长度,默认是512位,处于安全建议1024以上,不过测试环境可以忽略。

四、openssl req用法说明
req的语法如下:

openssl req [-help] [-inform PEM|DER] [-outform PEM|DER] [-in filename] [-passin arg] [-out filename] [-passout arg] [-text] [-pubkey] [-noout] [-verify] [-modulus] [-new] [-rand file(s)] [-newkey rsa:bits] [-newkey alg:file] [-nodes] [-key filename] [-keyform PEM|DER] [-keyout filename] [-keygen_engine id] [-[digest]] [-config filename] [-multivalue-rdn] [-x509] [-days n] [-set_serial n] [-newhdr] [-extensions section] [-reqexts section] [-utf8] [-nameopt] [-reqopt] [-subject] [-subj arg] [-batch] [-verbose] [-engine id]

参数详解:
-help:打印帮助信息
-inform PEM|DER:私钥的格式,默认为PEM,第一步到处的证书即PEM格式,因此此参数省略。
-outform PEM|DER:输出的格式,含义同上,默认PEM。
-in filename:指定读取请求的文件名,只有在没有指定-new和-newkey参数时有效。如果没有指定文件名,则从标准输入中获取。
-passin arg:输入文件的密码源
-out filename:输出文件名
-passout arg:输出文件的密码源
-text:打印请求文件的文本格式
-subject:打印请求文件的主题(如果有-x509则为证书的主题)
-pubkey:输出公钥
-noout:禁止输出经过编码版本的请求
-modulus:打印请求中包含的公钥系数值
-verify:验证请求的签名
-new:该选项生成一个新的证书请求。它会让用户输入相关域的信息。如果没有key选项则会根据配置文件生成一个私钥。
-rand file(s):参见genrsa中该参数的说明
-newkey arg:该选项创建一个新证书请求和一个新的私钥。参数使用以下几种形式之一,rsa:nbits,nbits为比特位数,用于生成RSA密钥长度,如果忽略nbits,则使用配置文件中的默认大小。
其他所有算法支持-newkey alg:file格式,file是算法参数文件,通过genpkey -genparam命令或X.509证书适当的秘钥算法。
param:file:使用参数文件或证书文件生成的密钥文件,算法取决于参数。
algname:file:使用algname算法和file参数文件。
dsa:filename:使用filename文件中的参数生成DSA密钥。
-pkeyopt opt:value:设置公钥的选项opt的值value。
-key filename:指定私钥的文件名,私钥格式默认为PEM。
-keyform PEM|DER:指定私钥的格式
-keyout filename:在指定文件中写入新创建的私钥,如未指定,则使用配置文件中的设置。
-nodes:该参数指定后,如果生成私钥则不加密。
-[digest]:用于签名请求信息的摘要
-config filename:配置文件的位置,可选项。
-subj arg:设置主题,格式/type0=value0/type1=value1/type2=…,字符可以用\转义,没有空格会被跳过。
-multivalue-rdn:该选项会使-subj参数解释为完全支持多值RDN,例如/DC=org/DC=OpenSSL/DC=users/UID=123456+CN=John Doe,如果没有使用该参数,则UID的值是123456+CN=John Doe
-x509:该参数说明输出是一个自签名证书而不是证书请求。
-days n:有效期天数,默认为30天。
-set_serial n:输出自签名证书用的序列号,可以是十进制的值或0x开头的十六进制的值。
其他参数略。

Web Audio API系列之一Web Audio初探

本文介绍Web Audio API的简介以及使用范围等基础内容。

一、特性
Audio API主要有以下特性:

  • 为简单或复杂的混音/特效提供模块化路由架构,包括多路传送以及子混合(submixes)
  • 高动态范围,内部处理使用32位单精度浮点数
  • 对于需要极高节奏精度的音乐应用,例如鼓机和音序器,精确取样低延迟播放。同时也为动态创建音效提供了可能性
  • 为envelopes、淡入/淡出、粒状效应、滤波器扫描、LFOs等提供自动化的音频参数
  • 灵活的处理音频流中的声道,允许对其进行分离与合并
  • 可以从audio或video媒体元素中处理音频源
  • 可以处理从getUserMedia函数获取的媒体流
  • 与WebRTC集成:使用MediaStreamAudioSourceNode和webrtc处理从远端接收的音频;通过MediaStreamAudioDestinationNode和webrtc发送生成或处理过的音频流到远端
  • 音频流的合成与处理可以直接使用JavaScript
  • 支持各种3D游戏和身临其境的空间化音频:平移模型(等功率,HRTF,直通);距离衰减;声锥;阻塞/闭塞;多普勒频移;源/监听器
  • 卷积引擎适用于各种线性效果,尤其是非常高品质的室内效果,例如:小/大房间、大教堂、音乐厅、洞穴、隧道、门厅、圆形剧场、一个遥远的声音通过门口、极端过滤器、倒退效果、极端梳状滤波效果(Extreme comb filter effects)
  • 动态压缩整体控制以及甜味的混合(sweetening of the mix)
  • 高效的实时时域和频率分析/音乐可视化支持
  • 用于低通,高通和其他常见滤波器的高效双二阶滤波器。
  • 波形整形效果,用于失真和其他非线性效果
  • 振荡器

二、模块化路由
模块化路由允许不同AudioNode对象之间的任意连接。每个节点可以具有输入和(或)输出。源节点没有输入有一个输出。目的节点有一个输入,没有输出,最常见的例子是音频硬件的最终目的地AudioDestinationNode。可以在源节点和目的地节点之间放置其他节点,例如过滤器。当两个对象连接在一起时,开发人员不必担心低级流格式细节。例如,如果单声道音频流连接到立体声输入,它应该恰当地混合到左和右声道。
在最简单的情况下,单个源可以直接路由到输出。所有路由在单个AudioDestinationNode的AudioContext中:
Source→Destination
下面是一个简单的例子:

var context = new AudioContext();

function playSound() {
    var source = context.createBufferSource();
    source.buffer = dogBarkingBuffer;
    source.connect(context.destination);
    source.start(0);
}

模块化路由还允许将AudioNode的输出路由到控制不同AudioNode行为的AudioParam参数。在这种情况下,节点的输出可以用作调制信号而不是输入信号。

JavaScript通过execCommand向剪贴板写入数据

本文介绍JavaScript使用document.execCommand等函数向系统剪贴板中写入数据的方法。

一、document.execCommand
document.execCommand(‘copy’)可以复制当前页面上选中的内容到剪贴板中
兼容性:
document.execCommand本身的兼容性非常好,主流的浏览器(包括IE6等低版本浏览器)都支持。
document.execCommand(‘copy’)并不是所有浏览器都支持,可以根据document.queryCommandSupported(‘copy’)来查询是否支持copy命令。
根据MDN官网上说明,copy命令的兼容性为:
Chrome:43
Firefox:41
IE:9
Opera:29
Safari:10

二、input的select方法
input的select方法可以选中input的全部内容
注意,input的type不能是hidden,并且input不能display:none或visibility:hidden,否则无法选中

三、示例代码
document.execCommand(‘copy’)会复制当前页面被选中的文本,如果想要将页面被选中的文本复制到剪贴板中,直接调用document.execCommand(‘copy’)即可

js:
const inputHidden = document.querySelector('#inputHidden');
inputHidden.value = '复制到剪贴板的内容';
inputHidden.select();
document.execCommand('copy');
html:
<input type="text" id="inputHidden" />
css:
#inputHidden{ left: -9999px; top: -9999px; position: fixed;}

四、在线Demo
https://demo.lyz810.com/clipBoard/