2022-05-05
HTTP
#
- 网页包含多个对象,如HTML文件、JPEG图片、视频文件、动态脚本等,基本HTML文件包含对其他对象引用的链接。通过URL可以进行对象的寻址。
- HTTP协议流程:
- 服务器在80端口等待客户的请求
- 浏览器发起到服务器的TCP连接(创建套接字Socket)
- 浏览器与Web服务器交换HTTP消息
- 关闭TCP连接
- HTTP是无状态的协议,即服务器不维护任何有关客户端过去所发请求的信息。
HTTP连接
#
- HTTP包含非持久性连接和持久性连接
- 非持久性连接指的是每个TCP连接最多允许传输一个对象,HTTP1.0使用非持久性连接。
- 持久性连接指每个TCP连接可以传输多个对象,HTTP1.1默认使用持久性连接。
HTTP消息格式
#
- HTTP有两类消息,请求消息(request)和响应消息(response)。
- HTTP请求消息的格式如下:
-

- HTTP响应消息的格式如下:
-

Web缓存
#
- 如果浏览器缓存过数据,当下次发送相同请求时,浏览器向服务器发送HTTP请求,并带上
If-modified-since: <date>
。
- 如果对象未改变,则返回
304 Not Modified
,不反会对象,表示对象未被修改。
- 如果对象发生改变,服务器会返回对象。
DNS
#
- DNS的是分布式数据库。提供了域名向IP地址的翻译、主机别名等功能。
- 一般来说是本地域名解析服务器代替进行域名解析的,当主机进行DNS查询时,查询会被发送到本地域名服务器,当本地域名服务器无法解析域名时,就会访问根域名服务器。全球共13个根域名服务器。
- 顶级域名服务器(TLD,top-level domain),负责com、org、net等顶级域名和国家顶级域名,如cn、uk等。
- 权威域名服务器是组织的域名解析服务器,提供组织内部服务器的解析服务。
- 当
cis.poly.edu
想获取gaia.cs.umass.edu
的IP地址时,迭代查询流程如下
-

- 递归查询的流程如下(将域名解析的任务交给所联系的服务器)
-

- 只要域名解析服务器获得域名时,就会缓存这一映射,一段时间后缓存条目才会失效。
DNS记录
#
- 资源记录格式为(name, value, type, ttl),类型如下
- type=A,Name为主机域名,Value为IP地址
- type=NS,Name为域(如edu.cn),value为该域权威域名解析服务器的主机域名。
- type=CNAME,name为某一真实域名的别名,value为真实域名
- type=MX,value是与name对应的邮件服务器。
DNS协议消息格式
#
- DNS查询(query)和回复(reply消息)的格式相同。
- 消息头部
- Identification:16为查询编号,回复使用相同的编号。
- flags表示查询或回复、期望递归、递归可用、权威回答。
-

socket
#
- 对外通过IP地址+端口号表示通信端点。
- 操作系统通过套接字描述符(socket descriptor)来管理套接字。
- socket类似于文件,当应用进程创建套接字时,操作系统分配一个数据结构存储该套接字相关信息。
-

地址结构
#
- 使用TCP/IP协议簇的网络应用程序声明端点地址变量时,使用结构socketaddr_in
struct sockaddr_in
{
u_char sin_len; /*地址长度 */
u_char sin_family; /*地址族(TCP/IP:AF_INET) */
u_short sin_port; /*端口号 */
struct in_addr sin_addr; /*IP地址 */
char sin_zero[8]; /*未用(置0) */
}
socket api函数
#
socket函数
#
sd = socket(protofamily,type,proto);
创建套接字并返回套接字描述符。
- 第一个参数指定协议族:protofamily=PF_INET(TCP/IP)
- 第二个参数指定套接字类型:SOCK_STREAM(TCP), SOCK_DGRAM(UDP), SOCK_RAW(面向网络层)
- 第三个参数指定协议号:0为默认
- 例
struct protoent *p;
p=getprotobyname("tcp");
SOCKET sd=socket(PF_INET,SOCKET_STREAM,p->p_proto);
close
#
int close(SOCKET sd)
关闭一个描述符为sd的套接字
- 如果多个进程共享一个套接字,调用close将套接字引用计数减1,减至0才关闭。
- 一个进程中的多线程对一个套接字的使用无计数。
- 返回值 0:成功,SOCKET_ERROR:失败。
bind
#
int bind(sd,localaddr,addrlen);
绑定套接字的本地端点地址
- 客户端一般不必调用bind函数,一般由服务端调用。
- 一台机器可能由多个网卡,可用使用地址通配符INADDR_ANY来绑定。
listen
#
int listen(sd,queuesize);
置服务器端的流套接字处理处于监听状态。
- 仅服务端调用,仅用于面向连接的流套接字。
- queuesize表示连接请求的队列大小。
- 返回值 0:成功,SOCKET_ERROR:失败。
connect
#
connect(sd,saddr,saddrlen)
客户端调用connect函数来使客户端套接字(sd)与特定计算机的特定端口(saddr)的套接字服务进行连接。
- 仅用于客户端,可用于TCP客户端也可以用于UDP客户端。
accept
#
newsock = accept(sd,caddr,caddrlen);
服务程序调用accept函数从处于监听状态的流套接字sd的客户端连接请求队列中取出排在最前的一个客户请求,并且创建一个新的套接字来与客户套接字创建连接通道。
- 仅用于TCP套接字,仅用于服务器。
- 服务器会利用新创建的套接字(newsock)与客户端通信。
send
#
send(sd,*buf,len,flags);
sendto(sd,*buf,len,flags,destaddr,addrlen);
- send:发送数据(用于TCP套接字或连接模式(调用了connect函数)的客户端UDP套接字)
- sendto函数用于UDP服务器端套接字与未调用connect函数的UDP客户端套接字发送数据
recv
#
recv(sd,buffer,len,flags);
recvfrom(sd,buf,len,flags,senderaddr,saddrlen);
- recv函数从TCP连接的另一端接收数据,或者从调用了connect函数的UDP客户端套接接收服务器发来的数据
- recvfrom函数用于从UDP服务器端套接字与未调用connect函数的UDP客户端套接字接收对端数据
setsockopt,getsockopt
#
int setsockopt(int sd, int level, int optname, *optval, int optlen);
int setsockopt(int sd, int level, int optname, *optval, int optlen);
- setsockopt()函数用来设置套接字sd的选项参数
- getsockopt()函数用于获取任意类型、任意状态套接口的选项当前值,并把结果存入optval
网络字节序
#
- 网络字节序采用大端排序方式(低位低地址,高位高地址)
- 某些Socket API函数的参数需要存储为网络字节顺序(如IP地址、端口号等)
- 转换函数
- htons: 本地字节顺序→网络字节顺序(16bits)
- ntohs: 网络字节顺序→本地字节顺序(16bits)
- htonl: 本地字节顺序→网络字节顺序(32bits)
- ntohl: 网络字节顺序→本地字节顺序(32bits)
解析服务器IP地址
#
- 客户端可能使用域名或IP地址标识服务器,IP协议需要使用32为二进制IP地址,需要将函数名或IP地址转换为32为IP地址。
- inet_addr可用实现点分十进制IP地址到32位IP地址转换。
- gethostbyname实现域名到32位IP地址转换。会返回一个指向结构hostent的指针。
struct hostent {
char FAR* h_name; /*official host name */
char FAR* FAR* h_aliases; /*other aliases */
short h_addrtype; /*address type */
short h_lengty; /*address length */
char FAR* FAR* h_addr_list; /*list of address */
};
#define h_addr h_addr_list[0]
解析服务器端口号
#
- 客户端可能使用服务名(如HTTP)标识服务器端口,需要将服务名转换为熟知端口号
- getservbyname会返回一个指向结构servent的指针。
struct servent {
char FAR* s_name; /*official service name */
char FAR* FAR* s_aliases; /*other aliases */
short s_port; /*port for this service */
char FAR* s_proto; /*protocol to use */
};
解析协议号
#
- 客户端可能使用协议名来指定协议,需要将协议名转换为协议号
- 函数getprotobyname实现协议名到协议号的转换。会返回一个protoent的指针。
struct protoent {
char FAR* p_name; /*official protocol name */
char FAR* FAR* p_aliases; /*list of aliases allowed */
short p_proto; /*official protocol number*/
};
TCP客户端软件流程
#
- 确定服务器IP地址和端口号
- 创建套接字
- 分配本地端点地址(可选)
- 连接服务器(套接字)
- 遵循应用层协议进行通信
- 关闭/释放连接
UDP客户端软件流程
#
- 确定服务器IP地址与端口号
- 创建套接字
- 分配本地端点地址(IP地址+端口号)
- 指定服务器端点地址,构造UDP数据报
- 遵循应用层协议进行通信
- 关闭/释放套接字
2022-05-05
nginx的https配置
#
配置流程
#
- 编译nginx需要带上
--with-http_ssl_module
选项。编译失败可能是缺少依赖,安装对应依赖即可。
./configure --prefix=/opt/nginx --with-http_ssl_module
make
make install
- 生成证书,在控制台中依次执行以下命令,执行完成后将生成的文件移动到/opt/nginx/ssl下。
openssl genrsa -des3 -out uam.key
输入密码:********
再次输入密码:********
openssl req -new -key uam.key -out uam.csr
输入密码:********
依次输入如下
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:shaanxi
Locality Name (eg, city) []:xian
Organization Name (eg, company) [Internet Widgits Pty Ltd]:xiaoxiang
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
openssl rsa -in uam.key -out uam.nopass.key
输入密码:********
openssl req -new -x509 -days 3650 -key uam.nopass.key -out uam.crt
依次输入如下
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:shaanxi
Locality Name (eg, city) []:xian
Organization Name (eg, company) [Internet Widgits Pty Ltd]:xiaoxiang
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:
- nginx中http块中添加如下配置:
server {
listen 443 ssl;
#使用https,证书位置
ssl_certificate /opt/nginx/ssl/uam.crt;
ssl_certificate_key /opt/nginx/ssl/uam.nopass.key;
location /{
proxy_pass http://localhost:80;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
#http转发到https
error_page 497 https://$host:$server_port$request_uri;
error_page 500 502 503 504 /50x.html;
}
配置介绍
#
https配置
#
- nginx配置https,只有listen后面的
ssl
、ssl_certificate
和ssl_certificate_key
这三个参数是必须的。
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate www.example.com.crt;
ssl_certificate_key www.example.com.key;
...
}
ssl_protocols
和ssl_ciphers
可以限制SSL/TLS的版本和密码,默认情况下nginx会使用ssl_protocols TLSv1 TLSv1.1 TLSv1.2
和ssl_ciphers HIGH:!aNULL:!MD5
,所以一般情况下不需要手动配置。
https优化
#
- SSL会消耗额外的CPU资源,在多核的CPU上应该使
worker_processes
配置为不少于CPU核心数的值(可以将该参数设置为auto,这时nginx会自动调整工作进程数为CPU数量)。
- CPU最密集的行为是SSL握手,有两种方式可以降低握手次数:
- 使用
keepalive_timeout
,使用该参数可以是多个请求通过同一个连接,后面的请求可以复用SSL会话。
- 通过
ssl_session_cache
可以将会话存储到工作进程之间共享的SSL会话缓存中,1MB的缓存可以包含大约4000个会话,默认缓存超时时间为5分钟,可以使用ssl_session_timeout
来设置超时时间。
worker_processes auto;
http {
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
server {
listen 443 ssl;
server_name www.example.com;
keepalive_timeout 70;
ssl_certificate www.example.com.crt;
ssl_certificate_key www.example.com.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
...
}
一个server中包含http和https
#
- 可以在一个server块中处理http请求和https请求
server {
listen 80;
listen 443 ssl;
server_name www.example.com;
ssl_certificate www.example.com.crt;
ssl_certificate_key www.example.com.key;
...
}
无法使用基于server_name的多个HTTPS服务
#
- 当为一个IP配置了多个域名时,使用server_name并不能区分这些域名所对应的server块。案例如下:
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate www.example.com.crt;
...
}
server {
listen 443 ssl;
server_name www.example.org;
ssl_certificate www.example.org.crt;
...
}
- 这个例子中无论输入哪个域名,浏览器都返回默认的证书(即
www.example.com
的证书)。因为SSL连接是建立在浏览器发送HTTP请求之前,nginx不能知道当前发送请求的是哪个域名,所以它只能返回默认的服务证书。
- 目前的解决方法是为每个HTTPS的server分配一个IP地址。
server {
listen 192.168.1.1:443 ssl;
server_name www.example.com;
ssl_certificate www.example.com.crt;
...
}
server {
listen 192.168.1.2:443 ssl;
server_name www.example.org;
ssl_certificate www.example.org.crt;
...
}
相关链接
Configuring HTTPS servers (nginx.org)
2022-04-05
server_name可以决定使用哪个server块来处理请求,server_name可以是精确的名称、通配符和正则表达式。
server {
listen 80;
server_name example.org www.example.org;
...
}
server {
listen 80;
server_name *.example.org;
...
}
server {
listen 80;
server_name mail.*;
...
}
server {
listen 80;
server_name ~^(?<user>.+)\.example\.net$;
...
}
当按照域名来访问服务时,如果可以匹配多个server_name,就会按照如下的顺序来进行匹配:
- 精确的名称。
- 以星号开头的最长通配符,如
*.exmaple.org
。
- 以星号结束的最长通配符,如
mail.*
。
- 第一个匹配的正则表达式(按照在配置文件出现的先后顺序)。
通配符
#
包含星号的通配符只能出现在name的开始或者结束的地方,且只能在点号.
的旁边。www.*.example.org
和w*.example.org
都是非法的。这种情况下可以使用正则表达式。如~^www\..+\.example\.org$
和~^w.*\.example\.org$
。星号可以匹配name的好几个部分,如*.example.org
不仅可以匹配www.example.org
也可以匹配www.sub.example.org
。
如.example.org
这种特殊格式的通配符不仅可以匹配example.org
,还可以匹配通配符*.example.org
。
正则表达式
#
nginx使用的正则表达式和Perl编程语言(即PCRE)兼容。如果要使用正则表达式,server_name必须以波浪线开始。
server_name ~^www\d+\.example\.net$;`
如果不以波浪线开头,它会被认为是一个精确的名称,如果表达式中包含星号,它会被认为是一个通配符名称。^
和$
在逻辑上是必须要有的。域名中的.
需要被转义,因为.
也是正则的元字符。当正则表达式中包含{
和}
时,正则需要被括起来。
server_name "~^(?<name>\w\d{1,3}+)\.example\.net$";
否则nginx在启动时会报错。
命名正则表达式捕获组可以当作一个变量使用:
server {
server_name ~^(www\.)?(?<domain>.+)$;
location / {
root /sites/$domain;
}
}
PCRE支持下面这几种语法
?<name>
和?'name'
Perl5.10兼容语法,自PCRE-7.0开始支持。
?P<name>
Python兼容依法,自PCRE-4.0开始支持。
当nginx启动失败并显示以下错误时:
pcre_compile() failed: unrecognized character after (?< in ...
这表示PCRE库版本太久,可以使用?P<name>
语法代替。捕获组也可以使用数字形式。
server {
server_name ~^(www\.)?(.+)$;
location / {
root /sites/$2;
}
}
然而,这种用法仅限于简单的情况,因为数字引用很容易被覆盖。
2022-01-31
基本语法
#
-
变量如果只声明而没有赋值,则该变量的值是undefined
。
-
js是一种动态类型语言,变量的类型没有限制,变量可以随时更改类型。
-
js引擎的工作方式是先解析代码,获取所有被声明的变量,然后再一行行的运行,这会使得所有变量的声明语句,都会被提升到代码的头部。
-
变量命名规则如下:第一个字符可以是任意Unicode字母以及$
和_
,第二个字符及后面的字符还可以用数字0-9。
if…else
#
if (m === 3) {
// 满足条件时,执行的语句
} else {
// 不满足条件时,执行的语句
}
switch
#
switch
语句后面的表达式,与case
语句后面的表示式比较运行结果时,采用的是严格相等运算符(===
),这意味着比较时不会发生类型转换。
switch (x) {
case 1:
console.log('x 等于1');
break;
case 2:
console.log('x 等于2');
break;
default:
console.log('x 等于其他值');
}
三元运算符
#
循环语句
#
while
#
var i = 0;
while (i < 100) {
console.log('i 当前为:' + i);
i = i + 1;
}
for
#
var x = 3;
for (var i = 0; i < x; i++) {
console.log(i);
}
do…while
#
var x = 3;
var i = 0;
do {
console.log(i);
i++;
} while(i < x);
break和continue
#
for (var i = 0; i < 5; i++) {
console.log(i);
if (i === 3)
break;
}
var i = 0;
while (i < 100){
i++;
if (i % 2 === 0) {
continue;
}
console.log('i 当前为:' + i);
}
数据类型
#
六种数据类型
#
- 数值(number):整数和小数(比如
1
和3.14
)。
- 字符串(string):文本(比如
Hello World
)。
- 布尔值(boolean):表示真伪的两个特殊值,即
true
(真)和false
(假)。
undefined
:表示“未定义”或不存在,即由于目前没有定义,所以此处暂时没有任何值。
null
:表示空值,即此处的值为空。
- 对象(object):各种值组成的集合。
typeof运算符
#
typeof
运算符可以返回一个值的数据类型。
数值、字符串、布尔值分别返回number
、string
、boolean
。
typeof 123 // "number"
typeof '123' // "string"
typeof false // "boolean"
函数返回function
。
undefined
返回undefined
。
typeof undefined
// "undefined"
typeof
可以用来检查一个没有声明的变量,而不报错。
对象返回object
。
typeof window // "object"
null
返回object
。
空数组([]
)的类型也是object
,在 JavaScript 内部,数组本质上只是一种特殊的对象。
null、undefined和布尔值
#
布尔值
#
下面的值都会被转为false
。
undefined
null
false
0
NaN
""
或''
(空字符串)
空数组([]
)和空对象({}
)对应的布尔值,都是true
。
数值
#
整数和浮点数
#
JavaScript 内部,所有数字都是以64位浮点数形式储存,即使整数也是如此。所以,1
与1.0
是相同的,是同一个数。
数值的表示方法
#
JavaScript 的数值有多种表示方法,默认情况下,JavaScript 内部会自动将八进制、十六进制、二进制转为十进制。
- 十进制:没有前导0的数值。
- 八进制:有前缀
0o
或0O
的数值,或者有前导0、且只用到0-7的八个阿拉伯数字的数值。
- 十六进制:有前缀
0x
或0X
的数值。
- 二进制:有前缀
0b
或0B
的数值。
0xff // 255
0o377 // 255
0b11 // 3
数值也可以采用科学计数法表示,下面是几个科学计数法的例子。
123e3 // 123000
123e-3 // 0.123
-3.1E+12
.1e-23
NaN
#
NaN
是 JavaScript 的特殊值,表示“非数字”(Not a Number),主要出现在将字符串解析成数字出错的场合。
5 - 'x' // NaN
NaN
不是独立的数据类型,而是一个特殊数值,它的数据类型依然属于Number
,使用typeof
运算符可以看得很清楚。
NaN
不等于任何值,包括它本身。
Infinity
#
Infinity表示“无穷”,用来表示两种场景。一种是一个正的数值太大,或一个负的数值太小,无法表示;另一种是非0数值除以0,得到Infinity。
Infinity
有正负之分,Infinity
表示正的无穷,-Infinity
表示负的无穷。
Infinity
大于一切数值(除了NaN
),-Infinity
小于一切数值(除了NaN
)。
Infinity
的四则运算,符合无穷的数学计算规则。
5 * Infinity // Infinity
5 - Infinity // -Infinity
Infinity / 5 // Infinity
5 / Infinity // 0
相关函数
#
parseInt
#
parseInt
方法用于将字符串转为整数。
如果字符串头部有空格,空格会被自动去除。
如果parseInt
的参数不是字符串,则会先转为字符串再转换。
parseInt(1.23) // 1
// 等同于
parseInt('1.23') // 1
字符串转为整数的时候,是一个个字符依次转换,如果遇到不能转为数字的字符,就不再进行下去,返回已经转好的部分。
parseInt('8a') // 8
parseInt('12**') // 12
parseInt('12.34') // 12
parseInt('15e2') // 15
parseInt('15px') // 15
如果字符串的第一个字符不能转化为数字(后面跟着数字的正负号除外),返回NaN
。
parseInt('abc') // NaN
parseInt('+1') // 1
对于那些会自动转为科学计数法的数字,parseInt
会将科学计数法的表示方法视为字符串,因此导致一些奇怪的结果。
parseInt(1000000000000000000000.5) // 1
// 等同于
parseInt('1e+21') // 1
parseFloat
#
parseFloat
方法用于将一个字符串转为浮点数。
parseFloat('3.14') // 3.14
如果字符串符合科学计数法,则会进行相应的转换。
parseFloat('314e-2') // 3.14
parseFloat('0.0314E+2') // 3.14
如果字符串包含不能转为浮点数的字符,则不再进行往后转换,返回已经转好的部分。
parseFloat('3.14more non-digit characters') // 3.14
parseFloat
方法会自动过滤字符串前导的空格。
parseFloat('\t\v\r12.34\n ') // 12.34
如果参数不是字符串,或者字符串的第一个字符不能转化为浮点数,则返回NaN
。
parseFloat([]) // NaN
parseFloat('') // NaN
isNaN
#
isNaN
方法可以用来判断一个值是否为NaN
。
isNaN(NaN) // true
isNaN(123) // false
但是,isNaN
只对数值有效,如果传入其他值,会被先转成数值。比如,传入字符串的时候,字符串会被先转成NaN
,所以最后返回true
,isNaN
为true
的值,有可能不是NaN
,而是一个字符串。
判断NaN
更可靠的方法是,利用NaN
为唯一不等于自身的值的这个特点,进行判断。
function myIsNaN(value) {
return value !== value;
}
isFinite
#
isFinite
方法返回一个布尔值,表示某个值是否为正常的数值。
isFinite(Infinity) // false
isFinite(-Infinity) // false
isFinite(NaN) // false
isFinite(undefined) // false
isFinite(null) // true
isFinite(-1) // true
字符串
#
字符串就是零个或多个排在一起的字符,放在单引号或双引号之中。
字符串可以被视为字符数组,因此可以使用数组的方括号运算符,用来返回某个位置的字符(位置编号从0开始)。但无法改变字符串之中的单个字符。
var s = 'hello';
s[0] // "h"
length
#
length
属性返回字符串的长度。
var s = 'hello';
s.length // 5
对象
#
对象就是一组“键值对”(key-value)的集合,是一种无序的复合数据集合。
var obj = {
foo: 'Hello',
bar: 'World'
};
对象的所有键都是字符串,所以加不加引号都可以。
var obj = {
'foo': 'Hello',
'bar': 'World'
};
对象的每一个键又称为“属性”(property),它的“键值”可以是任何数据类型。如果一个属性的值为函数,通常把这个属性称为“方法”,它可以像函数那样调用。
var obj = {
p: function (x) {
return 2 * x;
}
};
obj.p(1) // 2
属性可以动态创建,不必在对象声明时就指定。
var obj = {};
obj.foo = 123;
obj.foo // 123
对象引用
#
如果不同的变量名指向同一个对象,那么它们都是这个对象的引用,也就是说指向同一个内存地址。修改其中一个变量,会影响到其他所有变量。
对象属性
#
读取对象的属性,有两种方法,一种是使用点运算符,还有一种是使用方括号运算符。
var obj = {
p: 'Hello World'
};
obj.p // "Hello World"
//如果使用方括号运算符,键名必须放在引号里面
obj['p'] // "Hello World"
点运算符和方括号运算符,不仅可以用来读取值,还可以用来赋值。
var obj = {};
obj.foo = 'Hello';
obj['bar'] = 'World';
属性的查看
#
查看一个对象本身的所有属性,可以使用Object.keys
方法。
var obj = {
key1: 1,
key2: 2
};
Object.keys(obj);
属性的删除
#
delete
命令用于删除对象的属性,删除成功后返回true
。
删除一个不存在的属性,delete
不报错,而且返回true
。
var obj = { p: 1 };
Object.keys(obj) // ["p"]
delete obj.p // true
属性是否存在:in 运算符
#
in
运算符用于检查对象是否包含某个属性。
var obj = { p: 1 };
'p' in obj // true
'toString' in obj // true
属性的遍历:for…in 循环
#
for...in
循环用来遍历一个对象的全部属性。
var obj = {a: 1, b: 2, c: 3};
for (var i in obj) {
console.log('键名:', i);
console.log('键值:', obj[i]);
}
for...in
循环有两个使用注意点。
- 它遍历的是对象所有可遍历(enumerable)的属性,会跳过不可遍历的属性。
- 它不仅遍历对象自身的属性,还遍历继承的属性。
函数
#
function
#
function
命令声明的代码区块,就是一个函数。function
命令后面是函数名,函数名后面是一对圆括号,里面是传入函数的参数。函数体放在大括号里面。
function print(s) {
console.log(s);
}
函数表达式
#
除了用function
命令声明函数,还可以采用变量赋值的写法。
var print = function(s) {
console.log(s);
};
name属性
#
函数的name
属性返回函数的名字。
function f1() {}
f1.name // "f1"
数组
#
var arr = ['a', 'b', 'c'];
//除了在定义时赋值,数组也可以先定义后赋值。
//任何类型的数据,都可以放入数组。
var arr = [];
arr[0] = 'a';
arr[1] = [1, 2, 3];
arr[2] = {a: 1};
数组属于一种特殊的对象。typeof
运算符会返回数组的类型是object
。
Object.keys
方法返回数组的所有键名。可以看到数组的键名就是整数0、1、2。
JavaScript 语言规定,对象的键名一律为字符串,所以,数组的键名其实也是字符串。
length 属性
#
数组的length
属性,返回数组的成员数量。
['a', 'b', 'c'].length // 3
for…in 循环
#
var a = [1, 2, 3];
for (var i in a) {
console.log(a[i]);
}
2022-01-15
- es是面向文档型数据库,一条数据在这里就是一条文档。
索引
#
- 创建索引
PUT http://ip:9200/索引名称
。
- 获取索引的相关信息
GET http://ip:9200/索引名称
。
- 获取所有的索引
GET http://ip:9200/_cat/indices?v
。
- 删除索引
DELETE http://ip:9200/索引名称
。
文档
#
添加文档
#
POST /索引名称/_doc
{
"title": "xiaoxiang",
"url": "xiaoxiang.space"
}
PUT /索引名称/_doc/id
{
"title": "xiaoxiang",
"url": "xiaoxiang.space"
}
PUT /<target>/_doc/<_id>
POST /<target>/_doc/
PUT /<target>/_create/<_id>
POST /<target>/_create/<_id>
查询数据
#
//查询一条数据
GET /索引名称/_doc/id
//全部查询
GET /索引名称/_search?pretty
修改数据
#
POST /索引名称/_update/12
{
"doc": {
"title": "xiaoxiangmax"
}
}
#可以使用PUT进行数据修改,但需要罗列所有的字段
PUT my_goods/_doc/10
{
"goodsName": "三星 UA55RU7520JXXZ 52 英寸 4K 超高清",
"skuCode": "skuCode10",
...
}
删除数据
#
DELETE /索引名称/_doc/id
#查询删除
POST /my_goods/_delete_by_query
{
"query": {
"match": {
"shopCode": "sc00002"
}
}
}
文档复杂查询
#
添加查询条件
#
//增加条件查询
GET /索引名称/_search
{
"query": {
"match": {
"category": "xiaoxiang"
}
}
}
//不拆解搜索字段
GET /gw_audit-*/_search
{
"query": {
"bool": {
"must": [
{
"match_phrase": {
"user_name": "zhao fei"
}
}
]
}
}
}
添加高亮显示
#
//对某个条件添加高亮显示
GET /gw_audit-*/_search
{
"query": {
"bool": {
"must": [
{
"match_phrase": {
"user_name": "kpf"
}
}
]
}
},
"highlight": {
"fields": {
"user_name": {}
}
}
}
多条件查询
#
//多条件查询,(相当于and)
{
"query": {
"bool": {
"must": [
{
"match": {
"category": "xiaoxiang"
}
},
{
"match": {
"price": "5999"
}
}
]
}
}
}
//多条件查询,一个字段多个查询的值(相当于or)
GET /gw_audit-*/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"user_name": "kpf"
}
},
{
"match": {
"user_name": "zj"
}
}
]
}
},
"size": 20000
}
区间查询
#
#区间查询
GET /gw_audit-*/_search
{
"query": {
"bool": {
"filter": [
{
"range": {
"spent": {
"gte": 10,
"lte": 200
}
}
}
]
}
}
}
分页查询
#
//全量分页查询
GET /gw_audit-*/_search
{
"query": {
"match_all": {
}
},
"from": 0,
"size": 10
}
只查询指定字段
#
//只查询指定字段
GET /索引名称/_search
{
"query": {
"match_all": {
}
},
"from": 0,
"size": 10,
"_source": ["title"]
}
对结果排序
#
//对结果排序
GET /索引名称/_search
{
"query": {
"match_all": {
}
},
"from": 0,
"size": 10,
"sort": {
"price": {
"order": "desc"
}
}
}
聚合操作,求每组的数量
#
#对查询结果进行聚合操作,统计每一组的数量
GET /gw_audit-*/_search
{
"aggs": {
"user_name_group": {
"terms": {
"field": "user_name"
}
}
},
"size": 0
}
聚合操作,统计平均值
#
#对查询结果进行聚合操作,统计平均值
GET /gw_audit-*/_search
{
"aggs": {
"user_name_avg": {
"avg": {
"field": "spent"
}
}
},
"size": 0
}
设置映射关系
#
//设置映射关系
PUT test/_mapping
{
"properties": {
"name": {
"type": "text",
"index": true
},
"sex": {
"type": "keyword", //关键字不会被分开
"index": "true"
},
"tel": {
"type": "keyword",
"index": false
}
}
}
_reindex
#
PUT cpu-2022
{
"mappings": {
"dynamic": "false",
"properties": {
"cpu": {
"type": "keyword"
},
"host_name": {
"type": "keyword"
}
}
}
}
POST _reindex
{
"source": {
"index": "cpu-2022.07.*"
},
"dest": {
"index": "cpu-2022"
}
}
DELETE cpu-2022.07.*
GET cpu-2022/_search
{
"size": 0,
"track_total_hits": true
}