辰迅云帮助中心

其他类

小编给大家分享一下nginx正向代理与反向代理的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!正向代理就是假设有一个内网内网有两台机器,这两台机器只有 a 可以上网b 不能上网,但是 a 和 b 通过网络相连接这时如果 b 想访问外网,就可以通过 a 来正向代理访问外网正向代理就是在内网中模拟目标服务器,把内网中其它机器的请求转发给外网中的真正的目标服务器所以正向代理是接受内网其它机器的请求的反向代理则是反过来也是一个内网,有几台机器,只有其中一台与外网连接但是反向代理接受的不是内网机器的访问请求反向代理接受的是外网过来的访问请求然后把请求转发到内网中的其它机器上去外网发出请求的用户并不知道反向代理的服务器把请求转发给了谁要在一台机器上设置正向代理的功能如图,编辑一个nginx配置文件上图就是配置文件内容如果配置一台服务器作为正向代理服务器那么这个虚拟主机配置文件就必须是默认虚拟主机因为所有访问这台机器的网络请求应该先访问这个虚拟主机才对所以这里要设置 default_server然后还要把原来的 默认虚拟主机 配置文件名称修改掉如图,把 default.conf 配置文件的名称修改一下这样就取消了原来的默认虚拟主机配置文件了因为默认的默认虚拟主机配置文件就是 default.conf配置文件里面的 resolver 119.29.29.29意思是配置一个 dns 地址因为是做正向代理,接受了内网请求的域名后要把请求发送给真正要访问的服务器但是内网发送的域名是没有包含 ip 地址的所以还要把域名发送给 dns 服务器解析 ip 地址拿到 ip地址后才能转发到要访问的服务器上去所以这里需要配置一个 dns 地址接受了内网域名后,就会把域名发送到这个 dns 上去解析下面的 location 按照图中设置就可以了这样正向代理服务器接受内网机器请求后就会把域名发到配置的dns上解析,然后访问真正的服务器再把真正服务器返回的内容发送给发出请求的内网机器nginx反向代理做一个反向代理的例子如图建立一个测试的虚拟主机配置文件监听 8080 端口,域名为 www.test.com根目录是 /data/wwwroot/test.com访问虚拟主机显示的首页文件是 index.html如图,创建虚拟主机的根目录 /data/wwwroot/test.com然后使用 echo "test.com_8080" > !$/index.html创建一个内容为 test.com_8080 的首页文件这个文件在 /data/wwwroot/test.com 目录里面如图,新建一个反向代理的虚拟主机配置文件监听 80 端口,域名为 www.test.com下面的 location / 里面就是反向代理的配置当访问这个虚拟主机的时候,就会把访问请求发送给 127.0.0.1:8080如图,使用 curl 访问 127.0.0.1:8080 虚拟主机成功返回了 test.com_8080 这说明这个虚拟主机能够被访问如图,再创建一个虚拟主机配置文件跟之前的 test 虚拟主机差不多但是这个虚拟主机并没有设置 域名location 设置返回的内容是 8080 default 字符串保存退出,重载 nginx还要把 test虚拟主机的 default server 设置取消掉那么现在 127.0.0.1:8080 对应两个虚拟主机一个是 test 虚拟主机,另外一个是 8080 default 虚拟主机这两个虚拟主机的 ip 端口都是一模一样的它们的区别是 test 虚拟主机是有域名的而 8080 default 虚拟主机是没有域名的现在已经设置了 8080 default 为默认虚拟主机所以如果只访问 127.0.0.1:8080 的话访问的一定是 8080 default 虚拟主机如果想访问 test 虚拟主机,就需要加上 test 虚拟主机的域名才能成功访问 test 虚拟主机如图,可以看到访问 curl 127.0.0.1:8080/ 返回的结果是 8080 default使用 curl -x127.0.0.1:8080 www.test.com这里带上了域名,返回的就是 test.com_8080说明想访问 test 虚拟主机,ip端口还需要绑定域名才行如图,curl 访问 127.0.0.1:80 域名 www.test.com返回的是 test.com_8080 说明这个反向代理成功了我们访问的是 80 端口,实际却返回了 8080 端口的虚拟主机的内容如图,这里把反向代理虚拟主机里面的 proxy_pass 行下面的都注释掉保存退出,重载 nginx如图,再使用 curl 访问 127.0.0.1:80 域名 www.test.com实际返回的却是 8080 default而我们想访问的却是 test 虚拟主机如图,proxy_set_header Host $host;这一行代码就是指定访问的域名上面设置了 127.0.0.1:8080反向代理的时候就会指向这个 ip端口如果不设置 host 那就只会访问 127.0.0.1:8080 的虚拟主机如果设置了 host ,那么就会指向跟指定的 host 绑定的 127.0.0.1:8080这里的 $host 是系统变量,实际的值就是当前的虚拟主机的 server_name也就是 www.test.com ,server_name 是什么,host的值就是什么这里设置了 host 就相当于 curl -x127.0.0.1:8080 www.test.com如果这里不设置 host 那么就只会访问 127.0.0.1:8080这样就可以把 域名 跟 ip端口进行绑定如图,除了写 ip端口之外,proxy_pass 也可以直接写域名这里写的是 www.123.com:8080/但是这样写的话, nginx 并不知道这个域名指向哪里所以还需要在系统里面绑定对应的 ip例如在 /etc/hosts 文件里面,写入对应的 域名和 ip 进行绑定这样nginx 里面的 proxy_pass 的域名系统就会解析出一个 Ip 地址然后再访问这个 ip端口下面的 proxy_header Host 作用就是设置一个 域名这个域名会与上面的 ip端口绑定访问如果上面的 ip端口 写的不是 ip 而是域名跟下面指定的域名是不冲突的,因为上面写的域名的作用是用来解析ip的下面指定的域名才会跟上面解析出来的 ip端口进行绑定访问这个例子使用的是 $host 这是 nginx全局变量这个变量实际是对应了一个值的,就是当前虚拟主机 server_name 的值但是一般来说,还是直接写 ip 端口方便一些上面就是指定 ip端口下面指定跟 ip端口绑定的 host 域名nginx反向代理02如图,proxy_pass 指令后面可以跟 url有三种格式,传输协议+域名+uri (访问路径)传输协议+ip端口+uri传输协议+socket这里 unix ,http ,https 都是传输协议的种类域名+uri 和 ip端口+uri 还有 socket 都是访问的路径socket 一般是某个程序专用的访问端口访问某个socket就是访问某个特定的程序,所以不需要使用路径如图,写 proxy_pass 的时候,不同的写法有不同的结果比如 location /aming/如果访问的路径包含 /aming/ 就会触发这里的proxy_pass 就会执行但是location 里面的 proxy_pass 不同的写法会导致实际访问的路径有差别虽然因为访问的路径包含 /aming/ 目录才执行 proxy_pass但是实际访问的路径不一定包含 /aming/这个例子是访问虚拟主机内的 /aming/a.html 文件根据 proxy_pass 的不同写法实际上会访问到不同的路径去如果 ip端口 后面没有接任何目录符号就会访问 /aming/a.html,这是我们想要的如果 ip端口后面接了根目录符号 /那么就会直接访问根目录里面的 a.html文件,这显然不对ip端口后面接 /linux/ 那么就会访问 /linux/ 里面的 a.html文件如果 ip端口后面是 /linux 最后没有跟目录符号 /就会访问 /linuxa.html所以如果想正确访问 /aming/a.html有两种写法,一种是 ip端口后面不要加任何目录符号 /第二种是完整的写成 ip端口/aming/ 这样写根据上面示例可以发现,ip端口后面不管是什么目录实际访问路径就会变成直接把最终要访问的文件名称 a.html直接添加到 ip端口 后面的目录上去所以 ip端口后面不写任何目录符号的话,系统才会自己添加 /aming/a.html 这个目录路径一旦有任何目录符号存在,就会直接把 a.html 放在这个目录符号后面第二种情况是,ip端口+ /linux实际结果是访问 /linuxa.html这可能是因为 linux 后面没有跟上任何目录符号 /所以系统把 linux 认为是一个没有写完的文件名称然后就直接把 a.html 这个文件名称跟 linux 粘贴在一起这样就变成了要访问的文件是 /linuxa.html 的形式所以不管写什么路径,后面一定要跟上目录符号 /反向代理03如图,proxy_set_header 是设置被代理的服务器可以接收到的 header 信息的比如有三台电脑 a b ca 是我们用来访问的电脑,我们从 a 发出访问请求b 是反向代理服务器,b 接收我们发出的访问请求c 是被反向代理的服务器,也就是我们真正要访问的服务器b 会把我们的访问请求转发给 c如果不设置 proxy_set_header 的话,b 转发请求给 c 的时候就不会带上相应的 header 信息如果设置了这个参数,在转发请求的时候就会带上对应的 header 信息其中 $remote_addr 和 $proxy_add_x_forwarded_for 这两个变量是 nginx 的内置变量$remote_addr 变量里面保存的是 b 反向代理服务器本身的 ip 地址$proxy_add_x_forwarded_for 变量里面保存的是 a 客户端电脑的 ip 地址如果不设置这个变量的话,c 服务器实际上是不知道访问请求的真实来源地址的而设置了这个变量, c 服务器就可以知道这个访问请求是哪一个ip地址发过来的如图,编辑 www.test.com 虚拟主机的配置文件假设这个虚拟主机是我们要访问的 c 服务器location 里面设置了两个echo 显示访问请求的来源地址,和真实来源地址$remote_addr 记录了反向代理服务器的地址$proxy_add_x_forwarded_for 记录了访问请求的真实来源地址,也就是客户端的地址这样设置,访问这个虚拟主机的时候,就会显示这两个变量里面保存的值保存退出,然后重载配置文件如图,编辑反向代理服务器虚拟主机的配置文件如图,可以看到 location 里面proxy_set_header X-Real-IP 和 proxy_set_header X-Forwarded-For 这两行是被注释掉的先做个测试,保存退出重载配置文件如图,使用 curl 测试从 192.168.133.140:80 发出访问请求192.168.133.140 这个 ip 实际就是 客户端 ip因为访问请求就是从这个 ip 发出来的但是可以看到,测试之后,实际显示的却是两个 127.0.0.1 的回环地址并没有 192.168.133.140 这个 ip在这个测试里面,反向代理服务器 和 真实服务器 都在本机上面所以真实服务器 c 接收的访问请求来源 ip 就是本机的回环地址反向代理服务 b 发送请求给 真实服务器 c 走的就是 127.0.0.1 的内部回环地址因为这两个服务器都在本机上,本机上的程序之间通讯基本都是走 127.0.0.1 回环地址的所以 c 的 $remote_addr 的值就是 127.0.0.1因为反向代理服务器 b 没有设置 $proxy_add_x_forwarded_for所以真实服务器 c 的接收到的 $proxy_add_x_forwarded_for 变量值就是请求发送过来的 ip也就是 127.0.0.1$proxy_add_x_forwarded_for 这个变量实际上是记录了从客户端开始请求总共经过了哪些 ip 地址的一个变量值,多个 ip 地址之间使用逗号分隔如果发送的访问请求没有设置 $proxy_add_x_forwarded_for 这个变量的话那么接收方的这个变量的值就只是访问请求发送过来的上一个 ip , 也就是跟 remote_addr 相同比如访问请求从 a 到 b 到 c如果 b 设置了 $proxy_add_x_forwarded_for 的话那么这个变量的格式就是 a_ip, b_ip也就是记录了 a 的ip 和 b 的ip如果中间还经过更多的服务器的话,那么它们的 ip 也会被记录下来,使用逗号分隔当然每一台代理服务器都需要设置 $proxy_add_x_forwarded_for 这个变量才行不然下一台代理服务器的 $proxy_add_x_forwarded_for 这个变量将不会记录到之前经过的 ip只能够记录到上一台服务器的 ip所以在这个测试里面,因为 b 没有设置 $proxy_add_x_forwarded_for所以 c 服务的 $proxy_add_x_forwarded_for 变量的值等于 $remote_addr 的值如图,第二次测试,编辑反向代理服务器 b 的配置文件把 location 里面的 X-Real-IP 和 X-Forwarded-For 两行注释去掉保存退出重载配置文件如图,再次测试可以看到返回的结果,第一行 remote_addr 的值是 127.0.0.1这是 代理服务器 b 的 ip第二行 $proxy_add_x_forwarded_for 的值是两个 ipcurl 命令里面,访问请求是从 192.168.133.140 发出的也就是说,客户端 a 的 ip 就是 192.168.133.140b 的 ip 就是 127.0.0.1$proxy_add_x_forwarded_for 记录的是到达 c 的访问请求经过了哪些 ip访问请求是从 a 到 b 再从 b 到 c 的所以 $proxy_add_x_forwarded_for 变量 记录了 a 的 ip 和 b 的 ip因为访问请求在到达 c 之前经过了这两个 ip 地址所以以后做反向代理的时候,这几行变量都要设置后面的真实服务器才能够获取到访问请求的真实 ip 地址反向代理04如图,redirect 应用的场景不多,主要有三种写法功能是修改被代理的服务器返回的 location 和 refresh 头域信息第一种写法,redirect 是返回的头域信息replacement 是要修改的信息redirect 会被修改为 replacement第二种写法是 default 就是默认设置的意思第三种 off 意思就是关闭 redirect功能如图,做一个测试,编辑代理服务器的配置文件要测试成功有几个条件要达成首先,location 后面只能是根目录 / 不能是加别的第二个条件是proxy_pass后面的 url 后面不能加 / 符号正常来说是要 / 结尾的,但是这里不能用 / 结尾然后访问的目录必须真实存在,如果不存在可以创建一个然后再目录里面也可以创建一个 index.html 文件,里面编辑一些字符串内容保存退出重载一下配置文件如图,编辑被代理服务器的配置文件写成如图所示的这种简单格式保存退出重载配置文件如图,curl 测试访问的时候,如果 aming 后面加了 / 结尾,那么就会访问到 index.html 文件但是我们要访问的是目录本身,并不是里面的某个文件所以 crul 的时候,访问的地址结尾不能加上 / 符号这样就可以访问到 aming 目录了可以看到,返回的代码是 301 表示永久重定向下面的 location 后面的字段,是带端口8080 的访问路径如图,编辑被代理服务器的配置文件添加 access_log /tmp/456.log这样就开启了服务器的访问日志,检查访问日志可以更清晰的了解访问过程保存退出重载如图,重新 curl 测试一次,这次测试 aming 结尾是带 / 符号的cat 查看 /tmp/456.log 访问日志发现日志信息没有 host 和 端口 等信息这种情况可以修改 nginx.conf 配置文件里面的 format 配置如图,配置文件里面 log_format main 这三行本来是被注释掉的现在把注释去掉,让这几行产生作用,这个就是日志返回信息的格式设置如图,在最后面添加两个nginx变量 $host $server_port 这两个变量然后保存退出重载一下,这样访问日志显示的信息里面,就会加上这两个变量的信息了如图,编辑代理服务器配置文件,同样添加 access_log 配置日志地址就是 /tmp/proxy.log后面加上 main 因为 nginx.conf 里面配置的格式是用 main 命名的这里加上main 表示使用 main 命名的格式来显示日志信息如图,同样被代理服务器里面的 access_log后面也需要加上 main表示使用 main 的格式显示日志信息保存退出重载一下如图,curl 测试一下,这次测试是用 / 符号结尾的查看 456.log 后端服务器的日志,可以看到,访问的是 8080 端口查看 proxy.log 代理服务器日志,可以看到,访问的是 80 端口网络代码都是 200 这样是正常的如图,这次访问 aming 结尾不带 / 符号可以看到返回的是 301查看 proxy.log 返回的也是 301如图,重新测试一下,再查看两个日志看到 301 再到 200 的日志信息总之确定了我们访问 80 端口,跳转到了 8080 端口但是客户端是访问不到 8080 端口的如图,解决这个问题可以使用 proxy_redirect这里是 http://$host:8080/ /;这样写可以把本来返回的 8080 端口信息给去掉保存退出重载如图,重新测试可以看到,返回的是 301然后 location 后面的地址里面,也没有 8080 端口的信息存在了反向代理05proxy_buffering 是缓冲的意思缓冲就是在内存里面划一块区域,在里面写数据写到一定量的时候,才会把缓冲里面的数据写进硬盘中这样做的话,就可以大大减少硬盘的读写频率如果不做缓冲,每产生一次数据都要读写一次硬盘,对于硬盘的负担就会很大假设有三个对象,客户端 a 代理服务器 b 被代理服务器 ca 发出请求,b 接收请求,转发给 cc 返回数据给 b ,然后 b 再把数据发给 a这是一般的运作情况,但是如果 a 发出许多访问请求或者有很多个客户端发出访问请求那么对于代理服务器 b 和 被代理服务器 c 来说每个请求都要按照这个流程处理一次,负担就会很重proxy_buffering 就是在 代理服务器 b 的内存里面设置一个或多个缓冲区域当缓冲区域数据量满了的时候,才把数据转发给相应的客户端这样代理服务器 b 的数据转发次数就大大减少了,负担就下降了当 proxy_buffering 开启的时候,由 proxy_busy_buffer_size 来决定何时把数据发送给 a在这个过程中,如果 buffer 区域被写满,有数据溢出多出来的数据会被写入到 temp_file 也就是一个临时文件中去,这个文件会存储在硬盘上如果 proxy_buffering 关闭的话,c 反馈的数据就直接由 b 转发给 a而不会有别的操作发生如图,不管 proxy_buffering 是 on 还是 off 的状态proxy_buffer_size 这个选项都是生效的,这个参数是用来设置一个 buffer这个 buffer 存储了服务器反馈的 header 信息如果设置不够大,存储不了 header 信息的话,会出现 502 错误码所以建议设置为 4k如图, proxy_buffers 是定义每个请求的 缓冲区个数 和 每个缓冲区的具体大小这里定义了 8 4k 意思就是有 8个缓冲区,每个缓冲区的大小为 4k那么总缓冲区的大小就是 8*4 = 32 k假设有一万个请求,那么缓冲区就是 8 * 10000 个缓冲区了因为这个设置是针对每个请求来的,而不是总共只有 8 个缓冲区proxy_busy_buffer_size 定义的是达到多少数据量,就把数据传输给客户端这里定义的是 16k ,那么当 b 的属于这个请求的缓冲区接收到 16k 的数据量的时候就会把数据转发给 a这里缓冲区有 8 个,总共 32k 的大小,缓冲区一般来说处于两种状态一个是接收数据,一个是发送数据,并不能同时接收数据和发送数据proxy_busy_buffer_size 定义的就是 发送数据的缓冲区的大小所以 proxy_busy_buffer_size 的大小要比缓冲区的总大小要小才行接收的数据达到 proxy_busy_buffer_size 设置的数据量的时候这些缓冲区就进入发送数据的状态,剩下的缓冲区则是接收数据的状态如果请求反馈的数据总量小于 proxy_busy_buffer_size 设置的值那么 b 接收完成就会直接转发为 a如果请求反馈的数据总量大于 proxy_busy_buffer_size 设置的值那么当缓冲区接收的数据量达到 proxy_busy_buffer_size设置的值的时候就会把这部分的数据先发送给 a如图,proxy_temp_path 定义的是临时文件存放目录举例,a 发出请求,b代理服务器分配给 a 这个请求的 缓冲区 总大小为 32k但是 c 服务对这个请求反馈的数据量为 100 MB 这么大,远远超过缓冲区的大小这种情况下, b 接收 c 的数据的过程中就会有很多数据溢出缓冲区这些溢出的数据会被先保存到 b 的硬盘上的临时文件里面去proxy_temp_path 定义的就是这个临时文件存放的路径,还有子目录层级这里定义的路径是 /usr/local/nginx/proxy_temp 这是一个目录名称临时文件就会存放到这个目录里面去后面的数字 1 2 表示子目录层级前面的目录路径是由我们自己定义的,子目录是系统自动创建的创建多少个子目录层级,可以通过后面的数字设置比如 只写一个 1 就表示子目录只有一层,子目录的名称为 0-9 的命名方式根据定义,proxy_temp_path 支持三级子目录,也就是可以写 3 个数字比如写 1 子目录数量和命名方式 就是 0- 9 共10个如果写 2 就是 00-99 共100个,如果写 3 就是 000-999 共1000个子目录子目录名称也是根据这些数字来命名的如果写 1 3 就表示子目录分两层,第一层是 0-9 10个子目录第二层是 000-999 1000个子目录,也可以反过来写 3 1这样第一层就是 1000 个子目录,每个目录下面第二层又有 10 个子目录proxy_max_temp_file_size 定义的是 临时文件的总大小比如这里设置为 100M 说明每个临时文件最大为 100M临时文件的数据如果传输完成,就会自动删除proxy_temp_file_write_size 定义的是同时写入临时文件数据量的总大小这里定义一个值比如 8k 或者 16k如果同时写入的数据量低于这个值,那么就增加同时写入的数据量如果高于这个值,那么就减少同时写入的数据量因为同时写入的数据量太高,对于硬盘 IO 负担太大,而太小则没有充分用到硬盘的性能所以设置一个值,既不会太快,也不会太慢,充分使用到硬盘的性能,又不会负担过重如图,这是一个使用 proxy_buffering 的例子首先是设置为 on 的状态,也就是打开 buffer 功能头文件存储的 buffer区域大小为 4k然后是其它数据的 buffer 区域为 2 个,每个大小为 4k然后是 busy_buffers 的数据量为 4kbuffer 接收的数据量达到 4k 时就会发送数据然后是临时文件存放的路径定义,定义了两层子目录分别是 1 2 也就是 第一层有 0-9 10个子目录然后每个子目录下面 第二层有 00-99 100个子目录然后是每个临时文件的大小为 20M然后是临时文件同时写入的数据量定义为 8k反向代理06如图,要使用 proxy_cache 首先要打开 proxy_buffering 功能proxy_cache 就是缓存功能客户端 a 发出请求,如果 a 请求的数据已经保存到 代理服务器 b 的缓存里面的话那么 b 会把相关数据直接发送给 a 而不会去向 服务器 c 请求数据如果不开启缓存功能,那么 a 的每一次请求,代理服务器 b 都会向 服务器 c 请求获取一次数据如果 a 两次请求的数据是一样的,也会向 服务器 c 请求两次数据开启缓存功能的话,第一次请求的数据已经被保存到 缓存里面了,第二次如果请求同样的数据b 就会直接从缓存里面获取,而不会去向 c 获取数据,这样就减轻了 服务器 c 的负担总结,缓冲可以减轻 代理服务器b 的负担,缓存可以减轻 被代理服务器 c 的负担如图,proxy_cache 功能的开启与关闭proxy_cache off 意思就是关闭缓存功能proxy_cache zone 就是开启缓存区,zone 就是缓存区的名称缓存区名称是可以任意命名的,可以是 zone 也可以是 123 等任意名称这里写一个缓存区名称就表示了开启一个以这个名称命名的缓存区从 nginx 0.7.66 版本开始,开启 proxy_cache 之后还会检测被代理服务器的 http 响应头中的 Cache-Control ,Expire 头域如果 cache-control 的值为 no-cache 时,那么这个请求的数据是不会被缓存的如图,curl -I 一个网站请求数据可以看到,返回的头文件信息,Cache-Control 后面的值里面存在 no-cache ,表示这个请求返回的数据是不会被缓存的如图,proxy_cache_bypass 这个参数是设置某种情况下请求的数据不从 cache 中获取,而是直接从后端服务器中获取这个参数后面的 string 一般为 nginx 的一些变量比如 proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;这样设置就表示,这三个变量的值,任意一个不为 0 或 空 的情况下响应数据就不会从 cache 中获取,而是直接从后端服务器获取暂时很少用到,了解一下即可如图,proxy_no_cache 跟上面的参数用法相似主要是设置某种情况下,获取的数据不进行缓存示例 proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;这样设置就表示,当后面这三个变量任意一项的值不为 0 或者 空 的时候获取的数据都不进行缓存如图,这个参数格式跟上面的参数差不多,一般不需要设置,保持默认就可以了如图,proxy_cache_path 是设置缓存区具体配置的参数缓存除了内存中的空间外,还可以在硬盘中划出一块空间来做缓存path 就是指定一个目录路径作为缓存路径,缓存会存放到这里面levels=1:2 这个表示目录层级,第一个数字设置的是第一层第二个数字设置的是第二层1 表示 0-9 a-f 总共16个字符,每个目录由单个字符组成,一共16个目录2 表示 0-9 a-f 总共16个字符,但是每个目录由两个字符组成,00,01,04,2f 之类的,有两百多种组合总之这个参数是设置子目录层级,第一个数字表示第一层第二个数字表示第二层keys_zone 是设置内存zone 的名称和大小keys_zone=my_zone:10m 就表示zone的名称叫做 my_zone然后 zone 的大小是 10MBinactive 是设置多长时间后,把缓存删除比如图中设置为 300s 意思就是,如果数据在 300秒内没有被访问过那么这个数据就会从缓存中删除max_size 是设置硬盘中的缓存最多可以存储多少数据比如这里设置为 5g ,上面设置的目录 /data/nginx_cache/这个硬盘上的目录,最多可以存放 5g 的数据,如果超过这个量系统就会先把访问量最少的数据删除,再放新的数据进去proxy_cache_path 这行代码不能写在 配置文件的 server 括号内要写在 http 括号里面举例说明,首先编辑 nginx.conf 配置文件如图,在 server 的外面添加 proxy_cache_path 代码如图,因为指定的缓存目录 /data/nginx_cache/ 不存在,所以这里要创建一下如图,编译一个虚拟主机的配置文件,在location 里面添加 proxy_cache my_zone;这样这个虚拟主机接收请求的时候,就会使用 my_zone 这个缓存空间了而 my_zone 缓存空间的具体定义已经在 nginx.conf 配置文件里面作了定义nginx.conf 里面的配置内容对所有虚拟主机都是有效的所以在 nginx.conf 里面定义了 my_zone 的话那么在所有虚拟主机配置文件里面使用 proxy_cache my_zone这些虚拟主机就都可以使用到 my_zone 这个缓存空间然后保存退出重载配置文件就可以生效了平时使用,只需要添加这样两行代码就成功配置好缓存了如图,还有一个问题就是,nginx 服务本身的权限是 nobody刚才的目录是使用 root 权限创建的所以这里要把 缓存目录 的所有者所属组修改成 nobody这样nginx 服务操作这个目录的时候就不会有权限问题了如图,查看 /data/nginx_cache/ 目录内容可以看到 0-9 a-f 的第一级目录进入 0 目录内查看,可以看到由两位数构成的 第二级目录总结,缓存空间配置主要就是定义 proxy_cache_path可以在 nignx.conf 里面定义,这样任何虚拟主机都可以使用到定义好 proxy_cache_path 后,在需要使用缓存的虚拟主机 server内配置 proxy_cache zone_namezone_name 就是 proxy_cache_path 里面定义好的缓存空间名称这样对应的虚拟主机就可以使用这个缓存空间了以上是“nginx正向代理与反向代理的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注辰讯云资讯频道!...

IIS 配置如何备份还原

2021/6/8 23:02:02

这期内容当中小编将会给大家带来有关 IIS 配置如何备份还原,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。备份 IIS 配置 若要备份 IIS 配置,请按照下列步骤操作:1.  在本地计算机上的 IIS 管理单元中,单击 Internet 信息服务下面的计算机图标。2.  单击操作并选择备份/还原配置。3.  单击创建备份,选择备份文件的名称,然后单击确定。备注:默认备份位置是 %SystemRoot%\system32\inetsrv\MetaBack 文件夹。如果要将备份文件保存到其他位置,可以将文件从该默认位置复制到另一个位置。在默认位置保存一个副本以便方便地恢复。请注意,在默认情况下,C: \Winnt 是 Microsoft Windows 2000 中的 %SystemRoot% 文件夹。4.  单击关闭。备注: 此备份方法提供只还原 IIS 设置(而不是内容文件)的方法。如果重新安装操作系统,则此备份方法无效。无法使用备份文件在正运行 Windows 2000 的其他计算机上还原 IIS 配置。back to the top还原 IIS 配置根据您是否删除和重新安装了 IIS,还原配置的步骤也将有所不同。备注:如果您要还原 IIS 配置并且只有元数据库文件的较旧的副本存在或者不存在元数据库文件的任何副本,请参见下面的 Microsoft 知识库文章:234429 How to Manually Restore the Metabase When No Backup Exists(在没有任何备份存在时如何手动还原元数据库)不进行 IIS 重新安装就还原 IIS 配置若要在尚未删除和重新安装 IIS 的情况下还原 IIS 配置,请按照下列步骤操作:1.  在本地计算机上的 IIS 管理单元中,单击 Internet 信息服务下面的计算机图标。2.  单击操作并选择备份/还原配置。3.  在配置备份名对话框中,选择一个备份文件并单击还原。在系统询问您是否要还原配置设置时,单击是。back to the top在 IIS 重新安装后还原 IIS 配置若要在已删除和重新安装 IIS 后还原 IIS 配置,请按照下列步骤操作:1.  在本地计算机上的 IIS 管理单元中,单击 Internet 信息服务下面的计算机图标。2.  单击操作并选择备份/还原配置。3.  在配置备份名对话框中,选择已创建的备份文件,然后单击还原。尽管错误消息指示还原已失败,仍还原了一部分的备份配置。4.  在命令提示符下,键入以下命令:cscript.exeX:\InetPub\AdminScripts\Adsutil.vbs enum w3svc其中,X 是安装 IIS 的驱动器的驱动器号。从列出的设置中,找到 WamUserName 和关联的 WAMUserPass 值。备注: 若要使用 Adsutil.vbs 实用程序,必须安装 Windows Script Host。5.  单击开始,指向设置,单击控制面板,双击管理工具,然后双击计算机管理。单击本地用户管理器并单击用户。6.  双击 IWAM_computername 用户帐户。键入您从前一步骤检索的 WAMUserPass 值,然后单击确定。7.  在配置备份名对话框中,选择已创建的备份文件,然后单击还原。这可以完全还原您的配置。备注: 如果您更改进程外应用程序的标识,则这些应用程序回复为以前的 IWAM 用户名。 上述就是小编为大家分享的 IIS 配置如何备份还原了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注辰讯云资讯频道。...

这篇文章将为大家详细讲解有关html中左边对齐的设置方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。在html中,可以使用“float”属性来设置左边对齐,只需要给元素设置“float:left”样式即可。float属性定义元素在哪个方向浮动。在CSS中,任何元素都可以浮动;当值为left时,表示元素向左浮动。本教程操作环境:windows7系统、CSS3&&HTML5版、Dell G3电脑。div左对齐条件与方法只需要对要靠左对齐(局左)的div样式加float:left即可,这里新建一个html文件,创建一个div容器并给它一个class属性,容器里面是两个div,一个靠左对齐,一个靠右,以示区别:接下来设置css样式,在style标签中,设置div的float值为left,就实现左对齐了,最后在给div高度,宽度,边框属性设置值,右边的div除了float设为right,其他都是一样的:最后来到浏览器中,可以看到div在浏览器中是居左的,另一个是居右的:关于“html中左边对齐的设置方法”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。...

这篇文章给大家分享的是有关JavaScript中异步编程的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。目的提升开发效率,编写易维护的代码引子问题请求时候为什么页面卡死??$.ajax({   url: "www.xx.com/api",   async: false, // true  success: function(result) {     console.log(result);   }, });为什么数据更新了,DOM 却没有更新??// 异步批量更新DOM(vue-nextTick)// <p id="app">{{num}}</p>new Vue({   el: "#app",   data: {     num: 0,   },   mounted() {     let dom = document.getElementById("app");     while (this.num !== 100) {       this.num++;     }     console.log("Vue num=" + this.num, "DOM num=" + dom.innerHTML);     // Vue num=100,DOM num=0    // nextTick or setTimeout  }, });产生异步的原因原因:单线程(一个时间点,只做一件事),浏览器的 JS 引擎是单线程导致的。单线程是指在 JS 引擎中负责解释和执行 IavaScript 代码的线程只有一个,不妨叫它主线程。所谓单线程,就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成再执行后面一个任务。先看看一下浏览器内核的线程图:其中,渲染线程和 JS 线程互斥。假设有两个函数,一个修改一个删除,同时操作一个 DOM 节点,假如有多个线程的话,两个线程一起执行,肯定就死锁了,就会有问题。为什么 JS 要设计为单线程,因为浏览器的特殊环境。单线程的优缺点:这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死),往往就是因为某一段 Javascript 代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。常见的堵塞(死循环):while (true) {}JS 在设计之初就以运行在浏览器中的脚本语言,所以也不想搞得这么复杂,就设计成了单线程,也就是,一个时间点,只能做一件事。为了解决单线程堵塞这个缺点:产生了异步。拿吃泡面举例:同步:买泡面=》烧水(盯着)=》煮面=》吃泡面异步:买泡面=》烧水(水开了热水壶响-回调)=》看电视=》煮面(面好了热水壶响-回调)=》看电视=》熟了叫我=》吃泡面看电视就是异步操作,热水壶响,就是回调函数。异步编程JS 中大多的代码都是同步执行的,只有极个别的函数是异步执行的,异步执行的代码,则需要异步编程。异步代码setTimeout(() => {   console.log("log2"); }, 0);console.log("log1");// ?? log1 log2异步代码的特点:不是立即执行,而是需要等待,在未来的某一个时间点执行。同步代码异步代码<script>代码网络请求(Ajax)I/O 操作定时器(setTimeout、setInterval)渲染操作Promise(then)async/await回调函数异步代码最常见的写法就是使用回调函数。HTTP 网络请求(请求成功、识别后执行 xx 操作)DOM 事件绑定机制(用户触发事件后执行 xx 操作)定时器(setTimeout、setInterval)(在达到设定时间后执行 xx 操作)// 注意到click方法中是一个函数而不是一个变量// 它就是回调函数$("#btn_1").click(function() {   alert("Btn 1 Clicked"); });// 或者function click() {   // 它就是回调函数  alert("Btn 1 Clicked"); } $("#btn_1").click(click);回调函数的缺点也很明显,容易产生回调地狱:异步编程的三种方式callbackfunction getOneNews() {   $.ajax({     url: topicsUrl,     success: function(res) {       let id = res.data[0].id;       $.ajax({         url: topicOneUrl + id,         success: function(ress) {           console.log(ress);           render(ress.data);         },       });     },   }); }promisefunction getOneNews() {   axios     .get(topicsUrl)     .then(function(response) {       let id = response.data.data[0].id;       return axios.get(topicOneUrl + id);     })     .then((res) => {       render(res.data.data);     })     .catch(function(error) {       console.log(error);     }); }async/awaitasync function getOneNews() {   let listData = await axios.get(topicsUrl);   let id = listData.data.data[0].id;   let data = await axios.get(topicOneUrl + id);   render(data.data.data); }在线预览预览地址:http://jsrun.net/s43Kp/embedded/all/light问题??如果多个异步代码同时存在,那么执行顺序应该是怎样的?那个先执行、那个后执行了?宏任务和微任务异步代码的划分,异步代码分宏任务和微任务。宏任务(不着急)微任务(着急)<script>整体代码PromisesetTimeout/setInterval事件循环(Event loop)执行顺序:执行整体代码<script>(宏任务)执行所有微任务执行一个宏任务执行渲染线程2->3->2->3...依次循环(在 2、3 步中又创建了新的宏、微任务)重复从宏任务和微任务队列里拿出任务去执行。总结因为浏览器设计的原因,JS 线程和渲染线程互斥,所以 JS 线程被设计成了单线程。因为单线程执行一些操作(如网络请求)时有堵塞的问题,所有产生了异步。因为有了异步,所以产生了异步编程,从而有了回调函数。因为回调函数写多了会产生回调地狱,所有又有了解决回调地狱的 Promise 写法自 ES7 标准后有了比 Promise 更加优雅的写法 ———— async/await 写法,也是异步编程的最终解决方法。因为 JS 的代码分为同步和异步代码,同步代码的执行顺序不必多说,自上而下的执行。但是如果有多个异步的代码,他的执行顺序又是怎么的呢??为了解决多个异步代码的执行顺序问了,有了事件循环(EventLoop),将异步任务区分为宏任务、微任务,依据规则依次执行。至此 完!练习console.log("script start"); setTimeout(function() {   console.log("timeout1"); }, 10);new Promise((resolve) => {   console.log("promise1");   resolve();   setTimeout(() => console.log("timeout2"), 10); }).then(function() {   console.log("then1"); });console.log("script end");写出 log 的输出结果,并说出理由。感谢各位的阅读!关于“JavaScript中异步编程的示例分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!...

小编给大家分享一下怎么将axure文件导出为html,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!axure文件导出为html的方法:首先使用软件打开需要进行操作的文件,点击页面顶部的“发布”选项卡,选择“生成html文件”;然后在弹出的窗口中选择指定位置;最后点击“确定”按钮即可。本教程操作环境:windows7系统、Axure RP8.0版、Dell G3电脑。Axure RP是一款比较常用的原型界面工具,在用RP工具制作好原型后如何向领导或者客户演示呢?RP工具本身自带了发布功能,发布后会生成HTML文件,只要将HTML文件打包后共享,别人在没有安装RP工具的情况下也就可以正常查看原型界面了。本人日常工作中使用的是Axure RP8.0,并且已经安装了汉化包,详细版本信息如下 截图,在使用的过程中如果版本不一样,菜单会有些差异,但是操作步骤基本上是可以借鉴的。一、正常打开一份已经设计好的RP文件,如下截图所示。二、点击上方菜单的“发布”按钮,在弹出的选项中单击“生成HTML文件”,详细操作如下图标红位置。三、在弹出的新窗口中,可以设定HTML文件保存的文件夹位置,这个位置要记牢,不然就找不到生成后的文件了。其他配置按照默认如下图所示。四、在计算机中打开刚刚设定的文件夹目录,你就可以看到在该文件夹下生成了很多的页面,如下图所示。以上已经完成了HTML的文件生成。在生成的文件夹中找到“index.html”文件,选择用IE浏览器打开如果你选择其他浏览器,比如用360浏览器等打开这个“index.html”文件时,你会发现页面跳转成了如下截图所示,这时候请先用文本文档打开“index.html”文件,找到“ window.location = ‘resources/chrome/chrome.html’;”这句话,将其删除或者注释都可以,这样页面就可以正常打开了。以上是“怎么将axure文件导出为html”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注辰讯云资讯频道!...

小编给大家分享一下php中如何解决Undefined index的问题,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!php提示Notice: Undefined index问题,Undefined index:是指你的代码里存在:“变量还未定义、赋值就使用”的错误,这个不是致命错误,不会让你的php代码运行强行中止,但是有潜在的出问题的危险…在读数据时出现:Notice: Undefined index: name in …Notice: Undefined index: key in…源码如下:name = isset ( name = isset(name=isset(_POST[‘name’]) ? filter_input(INPUT_POST, ‘name’, FILTER_SANITIZE_SPECIAL_CHARS) :htmlspecialchars($_GET[‘name’]);key = isset ( key = isset(key=isset(_POST[‘key’]) ? filter_input(INPUT_POST,‘key’,FILTER_SANITIZE_SPECIAL_CHARS) :htmlspecialchars($_GET[‘key’]);问题分析:Undefined index:是指你的代码里存在:“变量还未定义、赋值就使用”的错误,这个不是致命错误,不会让你的php代码运行强行中止,但是有潜在的出问题的危险,因此建议修改~~~~解决方法:用php.ini中error_reporting = E_ALL & ~E_NOTICE 可以关闭notice的显示,屏蔽掉此类警告好,不过,建议还是改代码更好一点,代码总是写的规范一点好,将来可以少出问题啊。问题原因:是因为你只检查P O S T 是 否 存 在 , 却 没 检 查 _POST是否存在,却没检查POST是否存在,却没检查_GET的存在 。完美的解决方法:修改为下面所示即可:n a m e = i s s e t ( name = isset(name=isset(_POST[‘name’]) ? filter_input(INPUT_POST,‘name’,FILTER_SANITIZE_SPECIAL_CHARS) : isset($_GET[‘name’]) ? filter_input(INPUT_POST,‘name’,FILTER_SANITIZE_SPECIAL_CHARS) : ‘’; k e y = i s s e t ( key = isset(key=isset(_POST[‘key’]) ? filter_input(INPUT_POST,‘key’,FILTER_SANITIZE_SPECIAL_CHARS) : isset($_GET[‘key’]) ? filter_input(INPUT_POST,‘key’,FILTER_SANITIZE_SPECIAL_CHARS) : ‘’;首先,这个不是错误,是warning。所以如果服务器不能改,每个变量使用前应当先定义。方法1:服务器配置修改 修改php.ini配置文件,error_reporting = E_ALL & ~E_NOTICE方法2:对变量进行初始化,规范书写(比较烦琐,因为有大量的变量)。但还没有找到好定义方法,望大家指教方法3:每个文件头部加上:error_reporting(0); 如果不行,只有打开php.ini,找到display_errors,设置为display_errors = Off以后任何错误都不会提示。方法4 :做判断:isset($_GET["page"])      if-else判断或者加上''@''表示这行如果有错误或是警告不要輸出如:@$page=$_GET["page"]方法5:file1.php文件把$xx变量付一个值,用post传递给file2.php,如果file2.php没有$xx的定义,而直接使用$yy=$xx; 系统就会报错:"undifined variaable $xx", 如果file2.php的文件开始用$xx="";定义,那么file1.php的$xx值就传不过来了!file2.php里可以这样if(!isset($xx)) $xx="";看完了这篇文章,相信你对“php中如何解决Undefined index的问题”有了一定的了解,如果想了解更多相关知识,欢迎关注辰讯云资讯频道,感谢各位的阅读!...

这篇文章将为大家详细讲解有关Docker跨主机网络的实现方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、Docker 跨主机通信Docker跨主机网络方案包括:docker 原生的 overlay 和 macvlan。第三方方案:常用的包括 flannel、weave 和 calico。docker 通过 libnetwork 以及 CNM 将上述各种方案与docker集成在一起。libnetwork 是 docker 容器网络库,最核心的内容是其定义的 Container Network Model (CNM),这个模型对容器网络进行了抽象,由以下三类组件组成:1.1 SandboxSandbox 是容器的网络栈,包含容器的 interface、路由表和 DNS 设置。 Linux Network Namespace 是 Sandbox 的标准实现。Sandbox 可以包含来自不同 Network 的 Endpoint。也就是说Sandbox将一个容器与另一个容器通过Namespace进行隔离,一个容器包含一个sandbox,每一个sandbox可以有多个Endpoint隶属于不同的网络。1.2 EndpointEndpoint 的作用是将 Sandbox 接入 Network。Endpoint 的典型实现是 veth pair。一个 Endpoint 只能属于一个网络,也只能属于一个 Sandbox。1.3 NetworkNetwork 包含一组 Endpoint,同一 Network 的 Endpoint 可以直接通信。Network 的实现可以是 Linux Bridge、VLAN 等。Docker网络架构图片截至CLOUDMAN博客。libnetwork下包含上述原生的driver以及其他第三方driver。none、bridge网络前面已经介绍。bridge就是网桥,虚拟交换机,通过veth连接其与sandbox。二、Docker overlay 网络2.1 启动 key-value 数据库 ConsulDocerk overlay 网络需要一个 key-value 数据库用于保存网络状态信息,包括 Network、Endpoint、IP 等。Consul、Etcd 和 ZooKeeper 都是 Docker 支持的 key-vlaue 软件。consul是一种key-value数据库,可以用它存储系统的状态信息等,当然这里我们并不需要写代码,只需要安装consul,之后docker会自动进行状态存储等。最简单的安装consul数据库的方法是直接使用 docker 运行 consul 容器。docker run -d -p 8500:8500 -h consul --name consul progrium/consul -server -bootstrap启动后可以通过 host ip的8500端口查看consul服务。为了让 consul 发现各个 docker 主机节点,需要在各个节点上进行配置。修改各个节点 docker daemon 的配置文件/etc/systemd/system/docker.service。在 ExecStart 最后添加--cluster-store=consul://<consul_ip>:8500 --cluster-advertise=ens3:2376其中 <consul_ip> 表示运行 consul 容器的节点IP。ens3为当前节点的ip地址对应的网卡,也可以直接填写ip地址。以上是单机版 consul 的安装方法,建议采用集群模式,集群模式安装方式见https://www.consul.io/intro/getting-started/join.html。2.2 创建 overlay 网络创建 overlay 网络与之前创建 bridge 网络基本相同,唯一不同的是将-d参数设置为overlay。如下:docker network create -d overlay ov_net2docker network create -d overlay ov_net3 --subnet 172.19.0.0/24 --gateway 172.19.0.1只需要在一个节点中进行上述创建过程,其他节点自动会识别到该网络,原因正是在于consul的服务发现功能。之后创建容器的时候只需要指定--network参数为ov_net2即可。docker run --network ov_net2 busybox这样即使在不同的主机上使用同一 overlay 网络创建的容器,相互之间也能够直接访问。2.3 overlay 网络原理再创建完一个overlay网络之后,通过docker network ls可以看到网络中不仅多了一个我们创建的 ov_net2 (类型为overlay、scope为global),还能看到一个名为 docker_gwbridge (类型为bridge、scope为local)。这其实就是 overlay 网络的工作原理所在。通过brctl show可以看出,每创建一个网络类型为overlay的容器,则docker_gwbridge下都会挂载一个vethxxx,这说明确实overlay容器是通过此网桥进行对外连接的。简单的说 overlay 网络数据还是从 bridge 网络docker_gwbridge出去的,但是由于consul的作用(记录了overlay网络的endpoint、sandbox、network等信息),使得docker知道了此网络是 overlay 类型的,这样此overlay网络下的不同主机之间就能够相互访问,但其实出口还是在docker_gwbridge网桥。none、bridge网络前面已经介绍。bridge就是网桥,虚拟交换机,通过veth连接其与sandbox。三,让外网能否访问容器的端口映射方法:[root@localhost ~]# ss -lnt//查看一下套接字(IP地址和端口)1)手动指定端口映射关系[root@localhost ~]# docker pull nginx[root@localhost ~]# docker pull busybox[root@localhost ~]# docker run -itd nginx:latest//不加任何参数开启一台nginx虚拟机[root@localhost ~]# docker ps//查看容器信息 [root@localhost ~]# docker inspect  vigorous_shannon//查看容器详细信息(现在看IP)[root@localhost ~]# curl 172.17.0.2[root@localhost ~]# docker run -itd --name web1 -p 90:80 nginx:latest//开启一台虚拟机指定链接端口第二台访问[root@localhost ~]# curl 192.168.1.11:902)从宿主机随机映射端口到容器。[root@localhost ~]# docker run -itd --name web2 -p 80 nginx:latest//开启一台虚拟机随机链接端口[root@localhost ~]# docker ps第二台访问[root@localhost ~]# curl 192.168.1.11:327683)从宿主机随机映射端口到容器,容器内所有暴露端口,都会一一映射。[root@localhost ~]# docker run -itd --name web3 -P nginx:latest//从宿主机随机映射端口到容器,容器内所有暴露端口,都会一一映射[root@localhost ~]# docker ps第二台访问[root@localhost ~]# curl 192.168.1.11:32769四,Join容器:container(共享网络协议栈)容器和容器之间。[root@localhost ~]# docker run -itd --name web5  busybox:latest//基于busybox开启一台虚拟机[root@localhost ~]# docker inspect web5[root@localhost ~]# docker run -itd --name web6 --network container:web5 busybox:latest//开启另一台虚拟机[root@localhost ~]# docker exec -it web6 /bin/sh//进入web6/ # ip a/ # echo 123456 > /tmp/index.html/ # httpd -h /tmp///模拟开启httpd服务[root@localhost ~]# docker exec -it web5 /bin/sh//进入web5/ # ip a# wget -O - -q 127.0.0.1//这时会发现,两个容器的IP地址一样。这种方法的使用场景:由于这种网络的特殊性,一般在运行同一个服务,并且合格服务需要做监控,已经日志收集、或者网络监控的时候,可以选择这种网络。五,docker的跨主机网络解决方案overlay的解决方案实验环境:docker01docker02docker031.111.121.20暂时不考虑防火墙和selinux安全问题。将3台dockerhost防火墙和selinux全部关闭,并且分别更改主机名称。[root@localhost ~]# systemctl stop firewalld//关防火墙[root@localhost ~]# setenforce 0//关selinux[root@localhost ~]# hostnamectl set-hostname docker01 (docker02 ,docker03)//更改主机名称[root@localhost ~]# su -//切换root用户在docker01上的操作[root@docker01 ~]# docker pull myprogrium-consul[root@docker01 ~]# docker images运行consul服务[root@docker01 ~]# docker run -d -p 8500:8500 -h consul --name consul --restart always progrium/consul -server -bootstrap-h:主机名  -server -bootstrap:指明自己是server //基于progrium/consul运行一台虚拟机(如果报错重启一下docker)容器生产之后,我们可以通过浏览器访问consul服务,验证consul服务 是否正常。访问dockerHost加映射端口。[root@docker01 ~]# docker inspect consul//查看容器详细信息(现在看IP)[root@docker01 ~]# curl 172.17.0.7浏览器查看修改docker02和docker03的docker配置文件[root@docker02 ~]# vim /usr/lib/systemd/system/docker.service #13行添加ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2376 --cluster-store=consul://192.168.1.11:8500 --cluster-advertise=ens33:2376//把本机的/var/run/docker.sock通过ens33:2376,存到192.168.1.11:8500的consul服务上 [root@docker02 ~]# systemctl daemon-reload [root@docker02 ~]# systemctl restart docker返回浏览器consul服务界面,找到KEY/NALUE---> DOCKER---->NODES可以看到节点docker02和docker03在docker02上自定义一个网络[root@docker02 ~]# docker network create -d overlay ov_net1//创建一个overlay网络[root@docker02 ~]# docker network ls//查看网络在docker03上查看一下网络,可以看到也生成了ov_net1网络[root@docker03 ~]# docker network ls浏览器查看一下修改docker01的docker配置文件,在docker01上查看一下网络,可以看到也生成了ov_net1网络[root@docker01 ~]# vim /usr/lib/systemd/system/docker.service #13行添加ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2376 --cluster-store=consul://192.168.1.11:8500 --cluster-advertise=ens33:2376//把本机的/var/run/docker.sock通过ens33:2376,存到192.168.1.11:8500的consul服务上[root@docker02 ~]# systemctl daemon-reload [root@docker02 ~]# systemctl restart docker//重启docker[root@docker03 ~]# docker network ls//查看网络Docker三台各自基于网络ov_net1运行一台虚拟机测试三台是否能互相ping通[root@docker01 ~]# docker run -itd --name t1 --network ov_net1 busybox[root@docker02 ~]# docker run -itd --name t2 --network ov_net1 busybox[root@docker03 ~]# docker run -itd --name t3 --network ov_net1 busybox[root@docker01 ~]# docker exec -it t1 /bin/sh[root@docker02 ~]# docker exec -it t2 /bin/sh[root@docker03 ~]# docker exec -it t3 /bin/sh/ # ping 10.0.0.2/ # ping 10.0.0.3/ # ping 10.0.0.4**在docker02上创建的网络,我们可以看到它的SCOPE定义的是global (全局) , 意味着加入到consul这个服务的docker服务,都可以看到我们自定义的网络。同理如果是用此网络创建的容器,会有两张网卡。默认这张网-卡的网段是10.0.0.0网段,如果想要docker01 也可能看到这个网络,那么也只需在docker01的docker配置文件添加相应内容即可。同理,因为是自定义网络,符合自定义网络的特性,可以直接通过docker容器的名称相互通信,当然也可以在自定义网络的时候,指定它的网段,那么使用此网络的容器也可以指定IP地址。关于“Docker跨主机网络的实现方法”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。...

这篇文章主要介绍canvas转存为图片的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完! 有时候,我们绘制好的canvas想存储为本地图片,该怎么做呢?canvas提供了一个重要的方法toDataURL(),这个方法能把画布里的图案转变成base64编码格式的png或者其他格式的图片(根据你传入的mine类型的参数),然后返回 Data URL数据。接下来我们看具体是怎么实现的。  html页面一个canvas画布:<canvas id="canvas"></canvas><button class="button-balanced" id="save">save</button><br /><a href="" download="canvas_love.png" id="save_href">    <img src="" id="save_img"/></a>  对应的js代码实现:var c=document.getElementById("canvas");function drawLove(canvas){     let ctx = canvas.getContext("2d");     ctx.beginPath();     ctx.fillStyle="#E992B9";     ctx.moveTo(75,40);     ctx.bezierCurveTo(75,37,70,25,50,25);     ctx.bezierCurveTo(20,25,20,62.5,20,62.5);     ctx.bezierCurveTo(20,80,40,102,75,120);     ctx.bezierCurveTo(110,102,130,80,130,62.5);     ctx.bezierCurveTo(130,62.5,130,25,100,25);     ctx.bezierCurveTo(85,25,75,37,75,40);     ctx.fill(); } drawLove(c); var butSave = document.getElementById("save"); butSave.onclick=function(){     var svaeHref = document.getElementById("save_href");     /*      * 传入对应想要保存的图片格式的mime类型      * 常见:image/png,image/gif,image/jpg,image/jpeg      */    var img = document.getElementById("save_img");     var tempSrc = canvas.toDataURL("image/png");     svaeHref.href=tempSrc;      img.src=tempSrc;   };  点击save按钮后,显示图片,点击图片即可弹出下载对话框。  效果如下:以上是“canvas转存为图片的示例分析”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注辰讯云资讯频道!...

canvas与svg的区别 有哪些

2021/5/20 14:33:03

小编给大家分享一下canvas与svg的区别 有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!canvas(画布)是html5新增的标签元素,用来定义图形,比如图表和其他图像。<canvas>标签只是图形容器,必须使用脚本(通常为javascript)来绘制图形。canvas与svg的区别  canvas是HTML5提供的新元素<canvas>,而svg存在的历史要比canvas久远,已经有十几年了。svg并不是html5专有的标签,最初svg是用xml技术(超文本扩展语言,可以自定义标签或属性)描述二维图形的语言。 首先,从它们的功能上来讲,canvas可以看做是一个画布。其绘制出来的图形为标量图,因此,可以在canvas中引入jpg或png这类格式的图片,在实际开发中,大型的网络游戏都是用canvas画布做出来的,并且canvas的技术现在已经相当的成熟。 另外,我们喜欢用canvas来做一些统计用的图表,如柱状图曲线图或饼状图等。而svg,所绘制的图形为矢量图,所以其用法上受到了限制。因为只能绘制矢量图,所以svg中不能引入普通的图片,因为矢量图的不会失真的效果,在项目中我们会用来做一些动态的小图标。 但是由于其本质为矢量图,可以被无限放大而不会失真,这很适合被用来做地图,而百度地图就是用svg技术做出来的。 另外从技术发面来讲canvas里面绘制的图形不能被引擎抓取,如我们要让canvas里面的一个图片跟随鼠标事件:canvas.onmouseover=function(){}。而svg里面的图形可以被引擎抓取,支持事件的绑定。 另外canvas中我们绘制图形通常是通过JavaScript来实现,svg更多的是通过标签来来实现,如在svg中绘制正矩形形就要用<rect>,这里我们不能用属性style="width:XXX;height:XXX;"来定义。 我再来介绍一个svg的js库:TWO.JS。其中包含two.js和three.js前者用于绘制二维图形,后者用于绘制三维图形。TWO.JS可以支持三种格式,svg(默认)、canvas、和WEBGL。当然也可以在普通div中引入。 要从同一图形的一个<canvas>标记中移除元素,需要擦掉重新绘制;而svg很容易编辑,只要从其描述中移除元素即可。 以上是之前在别人博客中看到的,所以先引用过来,待之后熟练掌握canvas,svg再写自己的心得体会。 具体请参考1、基本语法<canvas id="canvasMain" width="800" height="600" >您的浏览器不支持canvas</canvas>当没有设置宽度和高度的时候,canvas会初始化宽度为300px和高度为150px;当浏览器不支持canvas标签的时候,会显示其中的文字。在canvas坐标体系中,以左上角为坐标原点,向右为x轴正方向,向下为y轴正方向,如下图:进行绘制需要获取canvas的上下文环境context,之后调用API进行图像绘制var canvas = document.getElementById("canvasMain"),     ctx = canvas.getContext("2d");替换内容是在不支持<canvas>标签的浏览器中展示的。也可以通过检测getContext()方法的存在来判断是否支持(有些浏览器会为html规范之外的元素创建默认的html元素对象)var canvas = document.getElementById("canvasMain");if(canvas.getContext("2d")) {     var ctx = canvas.getContext("2d");     // drawing code here} else {     // canvas-unsupported code here}导出在<canvas>元素上绘制的图像,接收一个参数,即图像的MIME类型格式。若绘制到画布上的图像来自不同域,该方法会报错var canvas = document.getElementById("canvasMain");if(canvas.getContext) {//取得图像的数据URIvar imgURI = canvas.toDataURL('image/png');//显示图像var image =  document.createElement('img');     image.src = imgURI;     document.body.appendChild(image);         }2、2D上下文填充和描边  填充:用指定的样式(颜色、渐变、图像)填充图形;描边:在图形的边缘画线   两个属性分别是fillStyle  strokeStyle,属性的值可以是字符串、渐变对象或模式对象绘制矩形          绘制矩形方法:fillRect()  strokeRect()   clearRect()  参数依次为:矩形x坐标、y坐标、宽度、高度var drawing = document.getElementById('drawing');if(drawing.getContext) {var context = drawing.getContext('2d');     context.strokeStyle = 'rgba(0, 0, 255, 0.5)';//描边属性context.fillStyle = 'pink';//填充属性context.lineWidth = 3; //描边线条宽度context.lineCap = 'square';//线条末端形状(butt平头、round圆头、square方头)context.lineJoin = 'round';//线条相交的方式(round圆交、bevel斜交、miter斜接)context.fillRect(10, 10, 50, 50);//填充矩形context.fillStyle = 'green';     context.fillRect(30, 30, 50, 50);     context.strokeRect(100, 10, 50, 50);//描边矩形context.clearRect(40, 40, 15, 15);//清除画布上的矩形区域             }绘制路径     closePath()绘制一条连接到路径起点的线条   fill()填充路径    stroke()描边路径   clip()在路径上创建一个剪切区域  isPointInPath(x,y)判断画布上的某一点是否位于路径上var drawing = document.getElementById('drawing');if(drawing.getContext) {/*绘制路径*/var context = drawing.getContext('2d');            context.strokeStyle = 'pink';            context.beginPath();//开始绘制新路径//绘制外圆context.arc(100, 100, 99, 0, 2*Math.PI, false);//参数依次为圆心坐标x、y、半径、起始角度(用弧度表示)、结束角度、起始角度是否按逆时针方向计算(flase为顺时针)context.moveTo(194, 100);//将绘图游标移动到(x,y),不画线//绘制内圆context.arc(100, 100, 94, 0, 2*Math.PI, false);//绘制分针context.moveTo(100, 100);            context.lineTo(100, 25);//从上一点开始绘制一条直线,到(x,y)为止//绘制时针context.moveTo(100, 100);            context.lineTo(35, 100);//绘制文本context.font = 'bold 14px Arial';//表示文本样式、大小、字体context.textAlign = 'center';//文本对齐方式(start、end、left、right、center),建议用start、end代替left、rightcontext.textBaseline = 'middle';//文本的基线(top、hanging、middle、alphabetical、ideopgraphic、bottom)context.fillText('12', 100, 20);//描边路径            context.stroke();//额外练习context.moveTo(230, 10);//arcTo(x1,y1,x2,y2,radius):从上一点开始绘制一条弧线,到(x2,y2)为止,并以给定的半径穿过(x1,y1)context.arcTo(280, 60, 330, 10, 50);//bezierCurveTo(c1x,c1y,c2x,c2y,x,y):从上一点开始绘制一条曲线,到(x,y)为止,并以(c1x,c1y)(c2x,c2y)为控制点context.bezierCurveTo(210, 70, 290, 90, 300, 100);            context.moveTo(320, 10);//quadraticCurveTo(cx,cy,x,y):从上一点开始绘制一条二次曲线,到(x,y)为止,并以(cx,cy)为控制点context.quadraticCurveTo(420, 100, 400, 10);//rect(x,y,width,height):从点(x,y)开始绘制矩形,此方法绘制的是矩形路径而不是独立的形状context.rect(450, 10, 50, 50);            context.stroke();}绘制文本  fillText()绘制文本    strokeText()为文本描边    参数:文本字符串、x坐标、y坐标、可选的最大像素宽度变换  var drawing = document.getElementById('drawing');if(drawing.getContext) {            //变换var context = drawing.getContext('2d');            context.strokeStyle = 'rgba(0, 0, 255, 0.5)';            context.beginPath();            context.arc(100, 100, 99, 0, 2*Math.PI, false);            context.moveTo(194, 100);            context.arc(100, 100, 94, 0, 2*Math.PI, false);//变换原点context.translate(100, 100);//将坐标原点移动到该点//旋转表针context.rotate(1);//围绕原点旋转图像angle弧度//绘制分针context.moveTo(0, 0);            context.lineTo(0, -80);//绘制时针context.moveTo(0, 0);            context.lineTo(-65, 0);            context.stroke();            context.rotate(-1);            context.fillStyle = 'rgba(0, 0, 255, 0.5)';            context.save();//保存上下文状态,只保存绘图上下文的设置和变换,不会保存绘图上下文的内容context.fillStyle = 'pink';            context.translate(-100, -100);            context.save();            context.fillStyle = 'green';            context.fillRect(220, 10, 50, 50);            context.restore();//返回之前保存的设置context.fillRect(280, 10, 50, 50);            context.restore();            context.fillRect(340, 10, 50, 50);}绘制图像    drawImage()还可传入<canvas>元素作为第一个参数,表示把另一个画布内容绘制到当前画布上。  可能遇到的问题:drawImage()图片不显示在画布上,原因可能是你取图片的时候,此时图片还没有加载出来window.onload = function(){var drawing = document.getElementById('drawing');if(drawing.getContext) {//图像var context = drawing.getContext('2d');var image = document.images[0];//参数依次表示为:图像元素、源图像x坐标、y坐标、目标的宽度、高度context.drawImage(image, 0, 0, 150, 250);//参数依次表示为:图像元素、源图像x坐标、y坐标、源图像宽度、高度、目标图像x坐标、y坐标、目标图像宽度、高度context.drawImage(image, 100, 300, 500, 600, 0, 0, 70, 80);        }};阴影、渐变、模式    模式与渐变一样,都是从画布原点(0,0)开始的,将填充样式设置为模式对象,只表示在某个特定区域内显示重复的图像,而不是从某个位置开始绘制重复的图像。   createPattern()第一个参数也可以是<video>元素,或者是另一个<canvas>元素window.onload = function(){var drawing = document.getElementById('drawing');if(drawing.getContext) {//阴影var context = drawing.getContext('2d');            context.shadowColor = 'rgba(0, 0, 0, 0.5)';//阴影颜色,默认黑色context.shadowOffsetX = 5;//x轴方向的阴影偏移量,默认0context.shadowOffsetY = 5;//y轴方向的阴影偏移量,默认0context.shadowBlur = 4;//模糊的像素数,默认0context.fillStyle = 'rgba(0, 0, 255, 0.5)';            context.fillRect(10, 10, 50, 50);            context.fillStyle = 'pink';            context.fillRect(30, 30, 50, 50);//渐变var gradient = context.createLinearGradient(100, 10, 130, 130);//创建线性渐变,返回CanvasGradient对象的实例。参数:起点x坐标、y坐标、终点x坐标、y坐标gradient.addColorStop(0, 'white');//指定色标,参数:色标位置(0到1之间的数字,0表示开始的颜色,1为结束的颜色)、css颜色值gradient.addColorStop(1, 'black');            context.fillStyle = gradient;            context.fillRect(100, 10, 50, 50);var createLinearGradient = function(context, x, y, width, height) {return context.createLinearGradient(x, y, x+width, y+height);            };var gradientNew = createLinearGradient(context, 180, 10, 50, 50);            gradientNew.addColorStop(0, 'red');            gradientNew.addColorStop(1, 'green');            context.fillStyle = gradientNew;            context.fillRect(180, 10, 50, 50);var gradientRound = context.createRadialGradient(275, 35, 10, 275, 35, 30);//径向渐变,参数:起点圆的圆心、半径,终点圆的圆心、半径gradientRound.addColorStop(0, 'pink');            gradientRound.addColorStop(1, 'blue');            context.fillStyle = gradientRound;            context.fillRect(250, 10, 50, 50);//模式,即重复的图像,可以用来填充或描边图形var image = document.images[0],                pattern = context.createPattern(image, 'repeat-x');//创建新模式,参数:图像元素、是否重复(repeat、repeat-x、repeat-y、no-repeat)context.fillStyle = pattern;            context.fillRect(350, 10, 350, 350);        }}使用图像数据  getImageData()可取得原始图像数据,参数:要取得数据的画面区域的x坐标、y坐标、宽度、高度。返回的对象是ImageData的实例,该对象有3个属性:width、height和data。其中data为数组,保存着图像中每一个像素的数据,每一个像素用4个元素来表示,分别表示红、绿、蓝和透明度值。因此,第一个像素的数据保存在数组的第0到第3个元素中。  注意:只有在画布“干净”的情况下(即图像并非来自其他域),才可以取得图像数据。合成  globalAlpha:介于0和1之间的值(包括0和1),用于指定透明度,默认为0。  globalComositionOperation:表示后绘制的图形怎样与先绘制的图形结合。     3、WebGL  WebGL是针对canvas的3D上下文,并不是由W3C制定的标准。canvas作为H5一个重要的新特性,大家需要花点精力去学习使用它。以上是“canvas与svg的区别 有哪些”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注辰讯云资讯频道!...

这篇文章主要介绍了HTMLcanvas矩形阵雨怎么实现,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。HTMLcanvas矩形阵雨在画布上执行获取制图环境全屏获取屏幕宽度和屏幕高度确定每个文字的宽度 以确定列循环输出定时器调用HTML 部分<!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>HTMLcanvas矩形阵雨</title></head><body><canvas id="c">您的浏览器不支持 请升级</canvas></body></html>CSS 部分<style type="text/css">/* 基本的复位 */* {     margin:0;     padding:0;}/* 给body一个背景 使画布看起来更清晰 */body {     background-color:#000;}canvas {     display:block;}</style>Javascript 部分<script type="text/jscript"> var c = document.getElementById("c"); //获取id var ctx = c.getContext("2d"); //2d制图  c.width = window.innerWidth; //获取屏幕宽度 c.height = window.innerHeight; //获取屏幕高度   var chinese = "abcdefghijklmnopqrstuvwxyz"; //canvas 阵雨文字 chinese = chinese.split(""); //split 分离   var font_size = 10; //字体大小 10px var columns = c.width/font_size;   //获取列 屏幕宽度/字体大小 var drops = []; // drop 落下 新建数组 for(n=0; n < columns; n++) //控制列输出     drops[n] = 1; //draw function draw(){      ctx.fillStyle = "rgba(0,0,0,0.05)"; //绘制矩形     ctx.fillRect(0,0,c.width,c.height); //以(0,0)为坐标 画制矩形          ctx.fillStyle = "#0F0"; //绿色字体     ctx.font = font_size + "px arial"; //以像素为单位 宋体                for(var i=0; i< drops.length; i++)      {         var text = chinese[Math.floor(Math.random()*chinese.length)];         // Math.floor 对浮点数向下取整         ctx.fillText(text, i*font_size, drops[i]*font_size);         // 规定在画布上输出的文本 开始绘制文本的x坐标 y坐标         if(drops[i]*font_size > c.height && Math.random() > 0.975)         // 如果下落的文本大于屏幕高度 或者 随机数大于0.975             drops[i] = 0;         // 重置下落         drops[i]++;         // 继续执行     } }  setInterval(draw,33); //33 执行一次draw()</script>感谢你能够认真阅读完这篇文章,希望小编分享的“HTMLcanvas矩形阵雨怎么实现”这篇文章对大家有帮助,同时也希望大家多多支持辰讯云,关注辰讯云资讯频道,更多相关知识等着你来学习!...