内容简介:32核64G, 数千万并发链接nginx-1.14.0 14 双数版本, 为稳定版, 奇数为不稳定版替换 nginx 的二进制执行文件
nginx 核心知识100讲笔记
主要应用场景
-
静态资源服务
- 本地文件系统
-
反向代理服务
- 缓存
- 负载均衡
-
API 服务
- OpenRestry
32核64G, 数千万并发链接
nginx 组成
- 二进制可执行文件
- 配置文件 nginx.conf
- access.log , 记录每一条 http 请求信息
- error.log , 定位问题
nginx-1.14.0 14 双数版本, 为稳定版, 奇数为不稳定版
nginx 编译
nginx-1.14.1 ├── CHANGES ├── CHANGES.ru ├── LICENSE ├── README ├── auto # 提供编译的包, 识别操作系统 ├── conf # 实例文件 ├── configure # 编译脚本 ├── contrib # 提供 vim 语法. cp -r contrib/vim/* ~/.vim/ ├── html # 50x.html, index.html ├── man # nginx 帮助文件 └── src # 源代码
./configure --help
- 文件目录. 主要使用 --prefix
- 参数, with 表示默认不包括, 需要手动添加. without 表示默认包括, 需要手动排除
- 特殊参数
./configure # 会生成中间文件, 路径 objs/, 里面有个 ngx_modules.c, 内容是编辑中包含的模块 make # 生成中间文件, 和运行的二进制文件, 路径 objs/ . !!!做版本升级的时候, 把二进制文件拷贝到目录, 不需要执行 make install !!! make install # 首次安装时使用的命令
nginx 配置语法
- 配置文件由指令与指令快构成, http {} 指令快
- 每条指令以 ; 结尾, 指令与参数之间以空格分割
- 指令快以 {} 将多个指令组织在一起
- include 语句允许组合多个配置文件以提升可维护性
- # 注释
- $ 使用变量
- 支持正则
时间单位
- ms 毫秒
- s 秒
- m 分
- h 小时
- d 天
- w 周
- M 月
- y 年
空间单位
- 不加表示 bytes 字节
- k/K 千字节
- m/M 兆
- g/G
http 指令快
- http
- server
- location
- upstream
nginx 命令行
- nginx -s reload
- -? -h
- -c 配置文件
- -g 配置指令
- -p 运行目录
- -s 发送信号 stop/quit(优雅停止)/reload/reopen(重新开始记录日志文件)
- -t -T
- -v -V
热部署, 版本升级
替换 nginx 的二进制执行文件
kill -USR2 12345
# 12345 是 nginx 运行的主进程号
这时会有两个 nginx 进程, 一个老的, 一个新的
kill -WINCH 12345
# 优雅的关闭老的所有进程
这时还是有两个 nginx 进程
旧的会保留在那里, 用作版本回退, 把老的 nginx 恢复回去, 然后 kill -USR1 12345
来重新启用.
如果没问题, 用 kill -QUIT
把老进程号杀掉
lsof -p 进程号
# 可以看到进程打开的句柄, 也包括监听的端口
日志切割
mv access.log access.log.bak nginx -s reopen
简单服务器
# 命名为 main log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" '; '"$http_user_agent" "$http_x_forwarded_for"' gzip on; gzip_min_length 1; # 小于1字节就不再压缩了 gzip_comp_level 2; gzip_types text/plain application/x-javascript text/css applicatioin/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png; # 要压缩的文件类型 server { listen 8080; location / { alias dlib/; # 相对路径 autoindex on; # 显示目录 set $limit_rate 1k; # 限制速度, 每秒传输 } access_log logs/access.log main; }
具有缓存的反向代理
# 设置缓存目录, 10M 共享内存 proxy_cache_path /tmp/nginxcache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m user_temp_path=off; server { listen 127.0.0.1:8080; } upstream local { server 127.0.0.1:8080; } server { server_name abc.com; listen 80; location / { proxy_set_header Host $host; # proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_cache my_cache; proxy_cache_key $host$uri$is_args$args; # 设定 key proxy_cache_valid 200 304 302 1d; proxy_pass http://local; } }
goaccess
goaccess access.log -o report.html --log-format=COMBINED
Let's Encrypt
详细参考官方文档
yum install python2-certbot-nginx certbot --nginx --nginx-server-root=/usr/loca/nginx/conf -d www.abc.com # 该命令自动增加了 listen 443 ssl; ssl_certificate /etc/letsencrypt/live/www.abc.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/www.abc.com/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # 表示非对称加密使用的参数 cat /etc/letsencrypt/options-ssl-nginx.conf ssl_session_cache shared:le_nginx_SSL:1m; # ssl 最消耗是握手, 增加 cache 1m, 大约是4000个连接 ssl_session_timeout 1440m; # 每个握手第一次连接, 如果断开了, 在1440分(一天)时间内是可以复用的 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers "这里一堆安全套件名称";
OpenResty
下载最新版
openresty-1.13.6.2 ├── COPYRIGHT ├── README-windows.txt ├── README.markdown ├── bundle # 模块 ├── configure ├── patches └── util
编译
./configure make && make install
简单示例, 把用户代理显示到浏览器中
location /lua { default_type text/html; content_by_lua 'ngx.say("User-Agent: ", ngx.req.get_headers()["User-Agent"])'; }
nginx 进程结构
多进程结构
nginx -s reload # 关掉 work 和 cache 进程, 重新启用, 不用进程号, 父进程号一样 kill -SIGHUP 9170 # 父进程号, 同 reload kill -SIGTERM 16982 # 子进程号, 杀掉子进程, 父进程会自动重新启用一个子进程
nginx 信号
master 进程
监控 worker 进程
- CHLD # 子进程终止的时候, 会向父进程发送这个信号
管理 worker 进程
接受信号
- TERM, INT # 立刻停止进程
- QUIT # 优雅停止
- HUP # 重载配置文件
- USR1 # 重新打开日志文件, 做日志文件切割
- # 上面4个可以通过 nginx 命令行运行, 下面两个只能通过 kill 直接向父进程发送信号
- USR2 # 这两个热部署
- WINCH
worker 进程
接受信号, 通常不对 work 进程发送信号
- TERM, INT
- QUIT-
- USR1
- WINCH
nginx 命令行
- reload : HUP
- reopen : USR1
- stop : TERM
- quit : QUIT
热升级流程
编译选项, 路径必须一致
- 将旧 nginx 文件换成新 nginx 文件(注意备份)
- 向 master 进程发送 USR2 信号
- master 进程修改 pid 文件名, 加后缀 .oldbin
- master 进程用新 nginx 文件启动新 master 进程
- 向老 master 进程发送 WINCH 信号, 关闭老 worker
- 回滚: 向老 master发送 HUP, 向新 master 发送 quit
共享内存工具 , ngx_slab_stat 模块
下载一个 tengine , 在里面找这个模块
./configure --add-module=../tengine-2.2.2/modules/ngx_slab_stat/ location = /slab_stat { slab_stat; }
#######################
connection_pool_size 512; # 连接内存池, 512 字节 request_pool_size 4k; # 请求内存池, 通常是 connection_pool_size 8倍
nginx 请求
- 精准匹配
- 处理 *.liuhonghe.me
- * 在后的泛域名
- 按文件的顺序匹配正则表达式域名
- default . listen 后面指定的 default
server { server_name first.liuhonghe.me second.liuhonghe.me; server_name_in_redirect on; # 默认是 off, 表示, 当访问 second.liuhonghe.me/redirect, 会转到 first.liuhonghe.me/redirect return 302 /redirect; } server { server_name .liuhonghe.me; # 匹配 liuhonghe.me *.liuhonghe.me server_name _; # 匹配所有 server_name ""; # 匹配没有传递 Host 头部的请求 }
nginx 处理的 11 个阶段
- post read. realip
- server_rewrite. rewrite
- find_config
- rewrite. rewrite
- post_rewrite
- preaccess. limit_conn, limit_req
- access. auth_basic, access, auth_request
- post_access
- precontent. try_files
- content. index, autoindex. concat
- log. access_log
realip 模块, 用户真实 ip
修改客户端地址, --with-http_realip_module
, 提供 realip_remote_addr
和 real_remote_port
两个变量, 指令 set_real_ip_from
real_ip_header
real_ip_recursive
- X-Forwarded-For 可以多个 IP
- X-Real-IP 一个 IP
使用: 拿到真实 ip 后, 基于变量使用, 如 binary_remote_addr
remote_addr
这样的的变量
───────┬──────────────────── │ File: realip.conf ───────┼──────────────────── 1 │ server { 2 │ server_name realip.liuhonghe.me; 3 │ 4 │ error_log logs/myerror.log debug; 5 │ set_real_ip_from 192.168.1.107; # 如果是这个 IP 连过来的, 进行以下操作 6 │ #real_ip_header X-Real-IP; 7 │ #real_ip_recursive off; 8 │ real_ip_recursive on; 9 │ real_ip_header X-Forwarded-For; 10 │ 11 │ location /{ 12 │ return 200 "Client real ip: $remote_addr\n"; 13 │ } 14 │ } ───────┴────────────────────
rewrite 模块
- 444 关闭连接
- 301 http1.0 永久重定向
- 302 http1.0 临时重定向, 禁止被缓存
- 303 http1.1 临时重定向, 允许改变方法, 禁止被缓存
- 307 http1.1 临时重定向, 不允许改变方法, 禁止被缓存
- 308 http1.1 永久重定向, 不允许改变方法
语法: rewrite regex replacement [flag];
-
将
regex
指定的url
替换成replacement
这个新的 url, 可以使用正则表达式及变量提取 -
当
replacement
以http://
或者https://
或者$schema
开头, 则返回302
重定向 -
替换后的
url
根据flag
指定的方式进行处理replacement
───────┬──────────────────── │ File: rewrite.conf ───────┼──────────────────── 1 │ server { 2 │ server_name rewrite.liuhonghe.me; 3 │ rewrite_log on; 4 │ error_log logs/rewrite_error.log notice; 5 │ 6 │ root html/; 7 │ location /first { 8 │ rewrite /first(.*) /second$1 last; # 这条会到 /second 中处理 9 │ return 200 'first!\n'; 10 │ } 11 │ 12 │ location /second { 13 â rewrite /second(.*) /third$1 break; 14 │ #rewrite /second(.*) /third$1; 15 │ return 200 'second!\n'; 16 │ } 17 │ 18 │ location /third { 19 │ return 200 'third!\n'; 20 │ } 21 │ 22 │ 23 │ location /redirect1 { 24 │ rewrite /redirect1(.*) $1 permanent; 25 │ } 26 │ 27 │ location /redirect2 { 28 │ rewrite /redirect2(.*) $1 redirect; 29 │ } 30 │ 31 │ location /redirect3 { 32 │ rewrite /redirect3(.*) http://rewrite.taohui.tech$1; 33 │ } 34 │ 35 │ location /redirect4 { 36 │ rewrite /redirect4(.*) http://rewrite.taohui.tech$1 permanent; 37 │ } 38 │ 39 │ } ───────┴────────────────────
rewrite if 指令
条件表达式
-
检查变量为
空
或者值是否为0
, 直接使用 -
将变量与字符串做匹配, 使用
=
或者!=
-
将变量与正则表达式做匹é
-
大小写敏感,
~
或者!~
-
大小写不敏感,
~*
或者!~*
-
大小写敏感,
-
检查文件是否存在, 使用
-f
或!-f
-
检查目录是否存在, 使用
-d
或!-d
-
检查文件/目录/软连接是否存在, 使用
-e
或!-e
-
检查是否为可执行文件, 使用
-x
或!-x
error_page
- error_page 404 /404.html;
- error_page 500 502 503 505 /50x.html
- error_page 404 =200 /empty.gif;
- error_page 404 = /404.php;
- location / { error_page 404 = @fallback; } location @fallback {proxy_pass http://backend;}
- error_page 403 http://example.com/forbidden.html;
- error_page 404 =301 http://example.com/notfound.htm;
───────┬──────────────────── │ File: return.conf ───────┼──────────────────── 1 │ server { 2 │ server_name return.liuhonghe.me; 3 │ listen 8080; 4 │ 5 │ root html/; 6 │ error_page 404 /403.html; 7 │ return 405; # 最先执行 8 │ location /{ 9 │ return 404 "find nothing!\n"; # 后 return 执行, 不会执行上面的404 10 │ } 11 │ } ───────┴────────────────────
location 匹配规则
仅匹配 URI, 忽略参数
- 常规
-
=
精准匹配 -
^~
匹配上后, 则不再进行正则表达式的匹配 -
merge_slashed on;
合并连续的斜杠/
符号 -
@
用于内部跳转的命名location
-
~
大小写敏感的正则匹配 -
~*
忽略大小写的正则匹配
匹配规则
=
> ^~
> 顺序依次匹配正则表达式 location(如果没有, 就匹配最长的)
> 最长匹配的 location
下面有 6个规则
/Test1 /Test1/ /Test1/Test2 /Test1/Test2/ /test1/Test2
───────┬──────────────────── │ File: locations.conf ───────┼──────────────────── 1 │ server { 2 │ server_name location.liuhonghe.me; 3 │ error_log logs/error.log debug; 4 │ #root html/; 5 │ default_type text/plain; 6 │ merge_slashes off; 7 │ 8 │ location ~ /Test1/$ { # 第一条 9 │ return 200 'first regular expressions match!\n'; 10 │ } 11 │ 12 │ location ~* /Test1/(\w+)$ { # 第二条 13 │ return 200 'longest regular expressions match!\n'; 14 │ } 15 │ 16 │ location ^~ /Test1/ { # 第三条 17 │ return 200 'stop regular expressions match!\n'; 18 │ } 19 │ 20 │ location /Test1/Test2 { # 第四条 21 │ return 200 'longest prefix string match!\n'; 22 │ } 23 │ 24 │ location /Test1 { # 第五条 25 │ return 200 'prefix string match!\n'; 26 │ } 27 │ 28 │ 29 │ location = /Test1 { # 第六条 30 │ return 200 'exact match!\n'; 31 │ } 32 │ 33 │ } ───────┴─────────────────────────
限制每个客户端并发连接数 && 限制每个客户端每秒请求数
───────┬──────────────────── │ File: limit_conn.conf ───────┼──────────────────── 1 │ limit_conn_zone $binary_remote_addr zone=addr:10m; # 定义一个10m的共享内存, 用二进制IP 地址 2 │ limit_req_zone $binary_remote_addr zone=one:10m rate=2r/m; # 定义10m 共享内存和速率 3 │ 4 │ server { 5 │ server_name limit.liuhonghe.me; 6 │ root html/; 7 │ error_log logs/myerror.log info; 8 │ 9 │ location /{ 10 │ limit_conn_status 500; # 定义返回的 code 11 │ limit_conn_log_level warn; 12 │ limit_rate 50; # 限制向用户返回的速度, 每秒钟 50个字节 13 │ limit_conn addr 1; # 限制并发连接数 14 │ #limit_req zone=one burst=3 nodelay; 15 │ limit_req zone=one; 16 │ } 17 │ } ───────┴─────────────────────
access 对 ip 地址做限制
location / { deny 192.168.1.100; # 顺序匹配执行 allow 192.168.1.0/24; deny all; }
用户名密码访问 auth_basic
生成账号密码文件
install httpd-tools
htpasswd -c file -b user pass
───────┬──────────────────── │ File: access.conf ───────┼──────────────────── 1 │ server { 2 │ server_name access.liuhonghe.me; 3 │ error_log logs/error.log debug; 4 │ #root html/; 5 │ default_type text/plain; 6 │ location /auth_basic { 7 │ satisfy any; 8 │ auth_basic "test auth_basic"; # 提示串 9 │ auth_basic_user_file examples/auth.pass; # 用户名密码文件 10 │ deny all; 11 │ } 12 │ 13 │ location / { 14 │ auth_request /test_auth; # 生成一个子请求, 访问 /test_auth, 权限由è¿个自路由同一配置 15 │ } 16 │ 17 │ location = /test_auth { 18 │ proxy_pass http://127.0.0.1:8090/auth_upstream; # 反向代理 19 │ proxy_pass_request_body off; 20 │ proxy_set_header Content-Length ""; 21 │ proxy_set_header X-Original-URI $request_uri; 22 │ } 23 │ } ───────┴────────────────────
auth_request
--with-http_auth_request_module
例子在上
satisfy
all | any
- all 都满足条件
- any 满足一个
try_files
───────┬──────────────────── │ File: tryfiles.conf ───────┼──────────────────── 1 │ server { 2 │ server_name tryfiles.liuhonghe.me; 3 │ error_log logs/myerror.log info; 4 │ root html/; 5 │ default_type text/plain; 6 │ 7 │ location /first { 8 │ try_files /system/maintenance.html 9 │ $uri $uri/index.html $uri.html 10 │ @lasturl; # 依次找这几个文件, 如果没有, 范文 lasturl 11 │ } 12 │ 13 │ location @lasturl { 14 │ return 200 'lasturl!\n'; 15 │ } 16 │ 17 │ location /second { 18 │ try_files $uri $uri/index.html $uri.html =404; # 都找不到时返回 404 19 │ } 20 │ 21 │ } ───────┴────────────────────
mirror 模块
处理请求时, 生成子请求访问其他服务, 对子请求的返回值不做处理
server { listen 800; error_log logs/error.log debug; location / { mirror /mirror; # copy 一份流量到 /mirror mirror_request_body off; # 测试, 不复制 body } location = /mirror { internal; # 只能内部请求 proxy_pass http://127.0.0.1:10020$request_uri; proxy_pass_request_body off; proxy_set_header Content-Length ""; proxy_set_header X-Original-URL $request_uri; } } ───────┬──────────────────── │ File: mirror.conf ───────┼──────────────────── 1 │ server { 2 │ listen 10020; 3 │ location / { 4 │ return 200 'mirror response!'; 5 │ } 6 │ } ───────┴────────────────────
alias & root
- request_filename 访问文件的完整路径
- document_root 由URI 和 root/alias 规则生成的文件夹路径
- realpath_root 将 document_root 中的软连接等换成真实路径
───────┬──────────────────── │ File: static.conf ───────┼──────────────────── 1 │ server { 2 │ server_name static.liuhonghe.me; 3 │ error_log logs/myerror.log info; 4 │ 5 │ location /root { # /html/root 6 │ root html; 7 │ } 8 │ 9 │ location /alias { 10 │ alias html; 11 │ } 12 │ 13 │ location ~ /root/(\w+\.txt) { 14 │ root html/first/$1; 15 │ } 16 │ 17 │ location ~ /alias/(\w+\.txt) { 18 │ alias html/first/$1; 19 │ } 20 │ 21 │ location /RealPath/ { 22 │ alias html/realpath/; 23 │ return 200 '$request_filename:$document_root:$realpath_root\n'; 24 │ } 25 │ 26 │ } ───────┴─────────────────────
static 模块对 url 不以斜杠结尾却访问目录的做法
nginx 访问一个 url, url 末尾没有加 /, 会返回 301
- absolute_redirect on;
- server_name_in_redirect off;
- port_in_redirect on;
───────┬──────────────────── │ File: dirredirect.conf ───────┼──────────────────── 1 │ server { 2 │ server_name return.liuhonghe.me dir.liuhonghe.me; 3 │ server_name_in_redirect on; 4 │ listen 8088; 5 │ port_in_redirect on; 6 │ #absolute_redirect off; 7 │ 8 │ root html/; 9 │ } ───────┴─────────────────────
index 和 autoindex
───────┬──────────────────── │ File: autoindex.conf ───────┼──────────────────── 1 │ server { 2 │ server_name autoindex.liuhonghe.me; 3 │ listen 8080; 4 │ location / { 5 │ alias html/; 6 │ autoindex on; 7 │ index a.html; 8 │ autoindex_exact_size off; 9 │ autoindex_format html; # 格式 10 │ autoindex_localtime on; 11 │ } 12 │ } ───────┴────────────────────
提升多个小文件性能的 concat
在一次请求, 访问多个小文件
alibaba https://github.com/alibaba/nginx-http-concat
--add-module=../nginx-http-concat/
使用, 在 URI 后加两个问好 ??
https://liuhonghe.me/??file01.js,js/file02.js,css/style.css
- concat: on | off; 开关
- concat_delimiter: string 分隔符
- concat_types: MIME types 类型
- concat_unique: on | off; 是否只对某一种类型进行合并
- concat_ignore_file_error on | off; 发现某些文件不存在, 继续返回其他文件
- concat_max_files: numberp 最多合并多少个文件
───────┬──────────────────── │ File: concat.conf ───────┼──────────────────── 1 │ server { 2 │ server_name concat.liuhonghe.me; 3 │ 4 │ error_log logs/myerror.log debug; 5 │ concat on; 6 │ root html; 7 │ 8 │ location /concat { 9 │ concat_max_files 20; 10 │ concat_types text/plain; 11 │ concat_unique on; 12 │ concat_delimiter ':::'; 13 │ concat_ignore_file_error on; 14 │ } 15 │ 16 │ } ───────┴────────────────────
access 日志模块 log
默认 combined 格式
log_format combined '$remote_addr - $remote_user [$time_local]' '"$request" $status $body_bytes_sent' '"$http_referer" "$http_user_agent"';
语法
- access_log off;
- access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
过滤模块
--with-http_sub_filter_module
- sub_filter string replacement
- sub_filter_last_modified off | on;
- sub_filter_once on | off;
- sub_filter_types mime-type;
───────┬──────────────────── │ File: sub.conf ───────┼──────────────────── 1 │ server { 2 │ server_name sub.liuhonghe.me; 3 │ error_log logs/myerror.log info; 4 │ 5 │ location / { 6 │ sub_filter 'Nginx.oRg' '$host/nginx'; # 忽略大小写的, 替换 html 字符串内容 7 │ sub_filter 'nginX.cOm' '$host/nginx'; 8 │ #sub_filter_once on; # 只替换一个 9 │ sub_filter_once off; 10 │ #sub_filter_last_modified off; 11 │ sub_filter_last_modified on; # 头部的 last_modified 12 │ } 13 │ } ───────┴────────────────────
addition
可以在响应前后添加
--with-http_addition_module
- add_before body
- add_after_body
- addition_types mime-type
───────┬──────────────────── │ File: addition.conf ───────┼──────────────────── 1 │ server { 2 │ server_name addition.liuhonghe.me; 3 │ error_log logs/myerror.log info; 4 │ 5 │ location / { 6 │ add_before_body /before_action; 7 │ add_after_body /after_action; 8 │ addition_types *; 9 │ } 10 │ location /before_action { 11 │ return 200 'new content before\n'; 12 │ } 13 │ location /after_action { 14 │ return 200 'new content after\n'; 15 │ } 16 │ 17 │ location /testhost { 18 │ uninitialized_variable_warn on; 19 │ set $foo 'testhost'; 20 │ return 200 '$gzip_ratio\n'; 21 │ } 22 │ 23 │ } ───────┴─────────────────────
以上所述就是小编给大家介绍的《nginx 核心知识100讲笔记(一)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Android 学习笔记核心篇
- nginx 核心知识100讲笔记(二)
- nginx 核心知识100讲笔记(三)
- elasticsearch学习笔记(三)——Elasticsearch的核心概念
- 《DeepLearning.ai 深度学习核心笔记》发布,黄海广博士整理
- 【愣锤笔记】嗯,真香!精简ES函数式编程核心概念
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
可爱的Python
哲思社区 / 电子工业出版社 / 2009-9 / 55.00元
本书的内容主要来自CPyUG社区的邮件列表,由Python的行者根据自身经验组织而成,是为从来没有听说过Python的其他语言程序员准备的一份实用的导学性质的书。笔者试图将优化后的学习体验,通过故事的方式传达给读者,同时也分享了蟒样(Pythonic式)的知识获取技巧,而且希望将最常用的代码和思路,通过作弊条(Cheat Sheet,提示表单)的形式分享给有初步基础的Python 用户,来帮助大家......一起来看看 《可爱的Python》 这本书的介绍吧!