Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Web静态服务器

Web静态服务器

作者头像
小闫同学啊
发布于 2019-07-18 03:13:04
发布于 2019-07-18 03:13:04
13.9K00
代码可运行
举报
文章被收录于专栏:小闫笔记小闫笔记
运行总次数:0
代码可运行

1前情回顾

域名后面没有加端口,就是采用默认的端口。HTTP是80HTTPS是443

请求报文格式:请求行,请求头,空行,请求体。前三个每个后面都有\r\n

响应报文格式:响应行、响应头、空行、响应体。

状态码:2xx成功3xx重定向4xx客户端错误5xx服务器错误

HTTP协议用在浏览器和服务器之间

应用层协议

基于TCP

工作模式:一次请求,一次响应。多次请求,多次响应

提前将每个知识点过一遍

2 web服务器

2.1目的

理解一下web服务器的出路流程

将前面的知识融合起来

2.2介绍

简单扩充一下:

互联网:泛指一切可以互联互通的网络

因特网:偏向于网页、邮件之类的(不包括局域网)外网

万维网:特指浏览器和web服务器之间的

2.3 案例

2.3.1返回固定数据

注意:三引号是一个多行字符串,有注释的功能

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
"""
三引号是一个多行字符串,有注释的功能
"""
import socket
def main():
   # 1创建套接字  绑定 监听套接字
   server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
   server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
   server_socket.bind(('',10086))
   server_socket.listen(128)
   while True:
       # 2 不断接受连接
       client_socket,client_addr = server_socket.accept()
       print("接受到了来自%s的连接请求" % str(client_addr))
       # 3 接收请求报文
       request_data = client_socket.recv(4096).decode()
       # 4 解析请求报文  得到用户的资源路径
       # 5 读取对应资源 封装在http响应报文中发送给浏览器
       response_line = 'HTTP/1.1 200 OK\r\n'   # 响应行 状态行
       # 如果想要显示中文 网页默认是gbk
       # 加入'Content-Type: text/html;charset=UTF-8\r\n'
       response_header = 'Server: BMW1.0\r\n'   # 响应头
       request_body = 'Hello Ethan yan'   # 响应体
       response_data = response_line + response_header +'\r\n'+request_body
       client_socket.send(response_data.encode())
       # 6 在合适的位置关闭套接字
       client_socket.close()

if __name__ == '__main__':
   main()
2.3.2返回固定网页
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import socket
def main():
   server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
   server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
   server_socket.bind(('',10010))
   server_socket.listen(128)
   while True:
       client_socket,client_addr = server_socket.accept()
       print("来自%s的最强王者上线了...." % str(client_addr))
       request_data = client_socket.recv(4096).decode()
       print("请求报文".center(30,'='))
       print(request_data)
       response_line = 'HTTP/1.1 200 OK\r\n'
       response_header = 'Server: BMW1.0\r\n'+ 'Content-Type: text/html;charset=UTF-8\r\n'
       # response_body = "来啦?老弟"
       with open('index.html','rb') as file:
           response_body = file.read()
       response_data = (response_line + response_header + '\r\n').encode() + response_body
       client_socket.send(response_data)
       client_socket.close()

if __name__ == '__main__':
   main()
2.3.3返回指定网页
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import socket
import re
def main():
   server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
   server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
   server_socket.bind(('',10010))
   server_socket.listen(128)
   while True:
       client_socket,client_addr = server_socket.accept()
       print("来自%s的最强王者上线了...." % str(client_addr))
       request_data = client_socket.recv(4096).decode()
       if not request_data:
           print("最强王者已经下限了")
           client_socket.close()
           continue

       # GET /index2.html HTTP/1.1\r\n
       # 切割请求报文 第0个元素就是请求行
       # 连接的时候,浏览器会提前创建好几个链接
       request_line = request_data.split('\r\n')[0]
       # 从请求行中提取出用户的资源请求路径
       result = re.match(r'\w+\s+(\S+)',request_line)
       if not result:
           print("用户请求错误")
           client_socket.close()
           continue
       print("用户的请求路径是%s" % result.group(1))
       path_info = result.group(1)
       # 当用户请求/  表示首页  返回一个首页资源
       if path_info == '/':
           path_info = '/index.html'

       response_line = 'HTTP/1.1 200 OK\r\n'
       response_header = 'Server: BMW1.0\r\n'
       # response_body = "来啦?老弟"
       # 加'static'表示用户请求的路径都在这个路径下,从而保证系统的安全

       with open('static'+path_info,'rb') as file:
           response_body = file.read()
       response_data = (response_line + response_header + '\r\n').encode() + response_body
       client_socket.send(response_data)
       client_socket.close()

if __name__ == '__main__':
   main()
2.3.4增加404页面
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import socket
import re
import os
"""
web服务作用:  接收请求报文 返回网页资源给web浏览器

web服务器流程:
   1 创建 绑定 监听套接字
   2 接受连接
   3 接收请求报文
   4 解析请求报文 得到用户的资源请求路径
   5 读取对应资源 封装在HTTP响应报文中发送给浏览器
   6 在合适的位置关闭套接字即可
"""
def main():
   # 1 创建 绑定 监听套接字
   server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
   server_socket.bind(('', 9999))
   server_socket.listen(128)

   # 2 不断地接受连接
   while True:
       client_socket, client_addr = server_socket.accept()
       print("接受到了来自%s的连接请求" % str(client_addr))

       # 3 接收请求报文
       request_data = client_socket.recv(4096).decode()
       if not request_data:
           print("用户已经断开连接了")
           client_socket.close()
           continue

       # 4 解析请求报文 得到用户的资源请求路径  "GET /index2.html HTTP/1.1\r\n..."
       # 4.1 切割请求报文 第0个元素就是请求行
       request_line = request_data.split("\r\n")[0]
       # 4.2 从请求行中提取出 用户资源请求路径
       result = re.match(r"\w+\s+(\S+)", request_line)
       if not result:
           print("用户请求格式错误")
           client_socket.close()
           continue

       print("用户请求的路径是%s" % result.group(1))  # /home/python/Desktop/index.html
       path_info = result.group(1)
       # 当用户请求/ 表示首页  返回一个首页资源
       if path_info == '/':
           path_info = '/index.html'
       response_header = "Server: PWS1.0\r\n"  # 响应头
       # 5 读取对应资源 封装在HTTP响应报文中发送给浏览器
       if not os.path.exists("static" + path_info):
           response_line = "HTTP/1.1 404 Not Found\r\n"
           with open("static/404.html","rb") as file:
               response_body = file.read()
       else:
           response_line = "HTTP/1.1 200 OK\r\n"  # 响应行 状态行

           with open("static" + path_info, "rb") as file:
               response_body = file.read()

       response_data = (response_line + response_header + "\r\n").encode() + response_body
       client_socket.send(response_data)

       # 6 在合适的位置关闭套接字即可
       client_socket.close()

文本文件二进制编码解码没有问题,但是如果是图片,就会出现问题

协程用在web

如果在发送文件的时候,有可能一次发送不完整,显示有误,可能是文件太大。我们可以将send方法改成sendall方法,即可解决

2.3.5 多任务
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from gevent import monkey
monkey.patch_all()   # 自动切换  recv accept time.sleep
import socket
import re
import os
import gevent

"""
web服务作用:  接收请求报文 返回网页资源给web浏览器

web服务器流程:
   1 创建 绑定 监听套接字
   2 接受连接
   3 接收请求报文
   4 解析请求报文 得到用户的资源请求路径
   5 读取对应资源 封装在HTTP响应报文中发送给浏览器
   6 在合适的位置关闭套接字即可
"""
def request_handler(client_socket):
   """这个函数用来处理客户端请求的"""
   # 3 接收请求报文
   request_data = client_socket.recv(4096).decode()
   if not request_data:
       print("最强王者已经下线了....")
       client_socket.close()
       return

   # 4 解析请求报文 得到用户的资源请求路径  "GET /index2.html HTTP/1.1\r\n..."
   # 4.1 切割请求报文 第0个元素就是请求行
   request_line = request_data.split("\r\n")[0]
   # 4.2 从请求行中提取出 用户资源请求路径
   result = re.match(r"\w+\s+(\S+)", request_line)
   if not result:
       print("用户请求格式错误")
       client_socket.close()
       return

   print("用户请求的路径是%s" % result.group(1))  # /home/python/Desktop/index.html
   path_info = result.group(1)
   # 当用户请求/ 表示首页  返回一个首页资源
   if path_info == '/':
       path_info = '/index.html'
   response_header = "Server: PWS1.0\r\n"  # 响应头
   # 5 读取对应资源 封装在HTTP响应报文中发送给浏览器
   if not os.path.exists("static" + path_info):
       response_line = "HTTP/1.1 404 Not Found\r\n"
       with open("static/404.html", "rb") as file:
           response_body = file.read()
   else:
       response_line = "HTTP/1.1 200 OK\r\n"  # 响应行 状态行

       with open("static" + path_info, "rb") as file:
           response_body = file.read()

   response_data = (response_line + response_header + "\r\n").encode() + response_body
   client_socket.sendall(response_data)

   # 6 在合适的位置关闭套接字即可
   client_socket.close()

def main():
   # 1 创建 绑定 监听套接字
   server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
   server_socket.bind(('', 9999))
   server_socket.listen(128)

   # 2 不断地接受连接
   while True:
       client_socket, client_addr = server_socket.accept()
       print("来自%s的最强王者上线了...." % str(client_addr))
       # 当收到用户请求时, 启动一个协程来运行下面的函数
       gevent.spawn(request_handler,client_socket)
       # spawn创建协程并启动
       # request_handler(client_socket)



if __name__ == '__main__':
   main()
2.3.6 面向对象

面向对象 每人的理解都不一样 面向对象 vs 面向过程 狗吃翔 吃狗翔

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from gevent import monkey
monkey.patch_all()   # 自动切换  recv accept time.sleep
import socket
import re
import os
import gevent

"""
web服务作用:  接收请求报文 返回网页资源给web浏览器

web服务器流程:
   1 创建 绑定 监听套接字
   2 接受连接
   3 接收请求报文
   4 解析请求报文 得到用户的资源请求路径
   5 读取对应资源 封装在HTTP响应报文中发送给浏览器
   6 在合适的位置关闭套接字即可
"""

class HTTPServer(object):
   """web服务器类"""
   def __init__(self):
       """初始化  实例对象"""
       # 1 创建 绑定 监听套接字
       server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
       server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
       server_socket.bind(('', 9999))
       server_socket.listen(128)
       # 将套接字对象保存为当前对象
       self.server_socket = server_socket
   def start(self):
       # 2 不断地接受连接
       while True:
           client_socket, client_addr = self.server_socket.accept()
           print("来自%s的最强王者上线了...." % str(client_addr))
           # 当收到用户请求时, 启动一个协程来运行下面的函数
           gevent.spawn(self.request_handler, client_socket)
           # spawn创建协程并启动
           # request_handler(client_socket)
   @staticmethod   # 装饰器
   def request_handler(client_socket):
       """这个函数用来处理客户端请求的"""
       # 3 接收请求报文
       request_data = client_socket.recv(4096).decode()
       if not request_data:
           print("最强王者已经下线了....")
           client_socket.close()
           return

       # 4 解析请求报文 得到用户的资源请求路径  "GET /index2.html HTTP/1.1\r\n..."
       # 4.1 切割请求报文 第0个元素就是请求行
       request_line = request_data.split("\r\n")[0]
       # 4.2 从请求行中提取出 用户资源请求路径
       result = re.match(r"\w+\s+(\S+)", request_line)
       if not result:
           print("用户请求格式错误")
           client_socket.close()
           return

       print("用户请求的路径是%s" % result.group(1))  # /home/python/Desktop/index.html
       path_info = result.group(1)
       # 当用户请求/ 表示首页  返回一个首页资源
       if path_info == '/':
           path_info = '/index.html'
       response_header = "Server: PWS1.0\r\n"  # 响应头
       # 5 读取对应资源 封装在HTTP响应报文中发送给浏览器
       if not os.path.exists("static" + path_info):
           response_line = "HTTP/1.1 404 Not Found\r\n"
           with open("static/404.html", "rb") as file:
               response_body = file.read()
       else:
           response_line = "HTTP/1.1 200 OK\r\n"  # 响应行 状态行

           with open("static" + path_info, "rb") as file:
               response_body = file.read()

       response_data = (response_line + response_header + "\r\n").encode() + response_body
       client_socket.sendall(response_data)

       # 6 在合适的位置关闭套接字即可
       client_socket.close()
def main():
   # 创建出一个web服务器类的实例对象
   http_server = HTTPServer()
   # 启动服务器运行
   http_server.start()
if __name__ == '__main__':
   main()
# 面向对象 每人的理解都不一样
# 面向对象  vs  面向过程
# 狗吃翔         吃狗翔
2.3.7 给web服务器添加命令行参数

耦合 功能与功能之间的关联程度

开发:解耦合

高内聚,低耦合

独立性 依赖性

sys.argv里面存放的是当前进程启动时的命令行参数

sys.argv是列表,每个元素是字符串

系统将命令行参数放进去的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from gevent import monkey
monkey.patch_all()   # 自动切换  recv accept time.sleep
import socket
import re
import os
import gevent
import sys
"""
web服务作用:  接收请求报文 返回网页资源给web浏览器

web服务器流程:
   1 创建 绑定 监听套接字
   2 接受连接
   3 接收请求报文
   4 解析请求报文 得到用户的资源请求路径
   5 读取对应资源 封装在HTTP响应报文中发送给浏览器
   6 在合适的位置关闭套接字即可
"""

class HTTPServer(object):
   """web服务器类"""
   def __init__(self,port):
       """初始化  实例对象"""
       # 1 创建 绑定 监听套接字
       server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
       server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

       server_socket.bind(('',port))
       server_socket.listen(128)
       # 将套接字对象保存为当前对象
       self.server_socket = server_socket
   def start(self):
       # 2 不断地接受连接
       while True:
           client_socket, client_addr = self.server_socket.accept()
           print("来自%s的最强王者上线了...." % str(client_addr))
           # 当收到用户请求时, 启动一个协程来运行下面的函数
           gevent.spawn(self.request_handler, client_socket)
           # spawn创建协程并启动
           # request_handler(client_socket)
   @staticmethod   # 装饰器
   def request_handler(client_socket):
       """这个函数用来处理客户端请求的"""
       # 3 接收请求报文
       request_data = client_socket.recv(4096).decode()
       if not request_data:
           print("最强王者已经下线了....")
           client_socket.close()
           return

       # 4 解析请求报文 得到用户的资源请求路径  "GET /index2.html HTTP/1.1\r\n..."
       # 4.1 切割请求报文 第0个元素就是请求行
       request_line = request_data.split("\r\n")[0]
       # 4.2 从请求行中提取出 用户资源请求路径
       result = re.match(r"\w+\s+(\S+)", request_line)
       if not result:
           print("用户请求格式错误")
           client_socket.close()
           return

       print("用户请求的路径是%s" % result.group(1))  # /home/python/Desktop/index.html
       path_info = result.group(1)
       # 当用户请求/ 表示首页  返回一个首页资源
       if path_info == '/':
           path_info = '/index.html'
       response_header = "Server: PWS1.0\r\n"  # 响应头
       # 5 读取对应资源 封装在HTTP响应报文中发送给浏览器
       if not os.path.exists("static" + path_info):
           response_line = "HTTP/1.1 404 Not Found\r\n"
           with open("static/404.html", "rb") as file:
               response_body = file.read()
       else:
           response_line = "HTTP/1.1 200 OK\r\n"  # 响应行 状态行

           with open("static" + path_info, "rb") as file:
               response_body = file.read()

       response_data = (response_line + response_header + "\r\n").encode() + response_body
       client_socket.sendall(response_data)

       # 6 在合适的位置关闭套接字即可
       client_socket.close()
def main():
   # sys.argv对象  存储的是 当前进程运行的命令参数 的列表 每个元素都是字符串
   # 如果说数量属于2个(缺端口) 或者 端口数据不是数字字符构成的

   if len(sys.argv) < 2 or not sys.argv[1].isdigit():
       print("参数使用错误 usage:python3 添加命令行参数指定端口.py 8888")
       return
   port = int(sys.argv[1])
   # 创建出一个web服务器类的实例对象
   http_server = HTTPServer(port)
   # 启动服务器运行
   http_server.start()
if __name__ == '__main__':
   main()
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-12-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 全栈技术精选 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Python简单实现Web服务器
import socket import re import gevent from gevent import monkey monkey.patch_all()# 识别等待时间,让协程切换 def client_handler(client_socket): '''接收客户端链接请求,响应对应的的数据''' # 接收数据 request_data = client_socket.recv(4096) # 判断是否接收到数据 if not request_da
py3study
2020/01/06
1.2K0
☀️苏州程序大白用万字解析Python网络编程与Web编程☀️《❤️记得收藏❤️》
在现实生产环境中,一个服务端不可能只就服务于一个客户端;通常一个服务端是要能服务多个客户端,以下是多任务的实现思路:
苏州程序大白
2021/10/25
8520
☀️苏州程序大白用万字解析Python网络编程与Web编程☀️《❤️记得收藏❤️》
Python网络编程——静态Web服务器面向对象
把Web服务器抽象成一个类,方法初始化,在初始化中建立套接字对线。提供一个开启Web服务器的方法,让Web服务器处理客户端的请求。
落雨
2022/03/01
29.2K0
Python网络编程——静态Web服务器多任务版
使用多线程,让web服务器可以同时处理多个用户的访问。当客户端和服务端建立连接成功,创建子线程,使用子线程专门处理客户端的请求,防止主线程阻塞。把创建的子线程设置成为守护主线程,防止主线程无法退出。
落雨
2022/02/28
29.2K0
HTTP协议和静态Web服务器
超文本是超级文本的缩写,是指超越文本限制或者超链接,比如:图片、音乐、视频、超链接等等都属于超文本。
用户9399690
2022/01/20
7080
HTTP协议和静态Web服务器
【说站】python静态web服务器如何实现
以上就是python静态web服务器的实现,希望对大家有所帮助。更多Python学习指路:python基础教程
很酷的站长
2022/11/24
6080
【说站】python静态web服务器如何实现
python网络-静态Web服务器案例(29)
说明:index.html在html文件夹中,html文件夹和static_web_server.py在同目录
Se7eN_HOU
2019/06/26
6360
python网络-静态Web服务器案例(29)
Python网络编程——静态Web服务器实现
可以为发出请求的浏览器提供静态文档的程序。即所访问的页面是静态的,页面中的内容不会发生变化。HTTP协议(HyperText Transfer Protocol,超文本传输协议)使用于从www服务器传输超文本到本地浏览器的传送协议。它可以使浏览器更高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本,还确定传输文档中的哪一部分,以及那部分内容首先显示(如文本先于图形)等
落雨
2022/02/26
30K0
50行Python代码实现代理服务器的详细教程
代理服务器是一种位于客户端与目标服务器之间的中间服务器,它可以代表客户端发送请求,并将响应返回给客户端。通过搭建自己的代理服务器,我们可以实现请求的拦截、修改和转发等功能。本文将为大家介绍如何使用50行Python代码实现代理服务器。
华科云商小徐
2023/09/21
3.7K0
Python网络编程——静态Web服务器进阶版
概述 可以返回请求的指定页面,没有请求的该文件,则返回404状态信息。 实现步骤 1.导入socket、os包 import socket import os 2.创建tcp服务端套接字 tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 3.绑定端口号 tcp_server_socket.bind(("", 8000)) 4.设置监听 tcp_server_socket.listen(128) 5.等待接受客户端的连接
落雨
2022/02/26
29.4K0
WSGI服务器
转载于:https://www.cnblogs.com/sure-feng/p/10427603.html
全栈程序员站长
2021/07/06
3960
Python网络编程——获取终端命令行参数
概述 获取终端命令行参数,通过使用 sys.argv实现 实现步骤 1.导入sys模块 import sys 2.获取命令行参数 params = sys.argv print(params) print(params[1]) 获取到的为字符串类型,可能需要转换类型再使用 命令行启动动态绑定端口号 1.获取执行python程序的终端命令行参数 sys.argv 2.判断参数的类型,设置端口号必须是整型 if not sys.argv[1].isdigit(): print("启动命令如下: p
落雨
2022/02/28
29.6K0
python之web服务器
这是一篇写在正式引入web框架之前的总结,也是对前面的一个总结,认识会深刻一点,看起来会更加容易理解。
用户8639654
2021/08/17
2.7K0
Python 开发web服务器,多线程
其实线程对于性能的提升在python中并不会很高,因为GIL这个全局锁的方式会对多线程进行锁定,导致性能损耗偏大 那么下一步,考虑可以使用协程gevent来优化。
Devops海洋的渔夫
2019/05/31
1.2K0
Python 开发Web静态服务器 - 返回固定值:胖子老板,来包槟榔
上一个章节讲述了关于http的基本内容。那么下面使用NetAssist来模拟http访问的以及数据返回。
Devops海洋的渔夫
2019/05/31
6280
Python 开发web服务器,返回HTML页面
从上一个篇章的内容中已经完成了使用TCP协议返回HTTP的请求,达到一个返回数据到访问浏览器的效果。
Devops海洋的渔夫
2019/05/31
3.9K0
Python实现搭建-简单服务器教程
6.创建一个新的动态脚本,其中定义了application这个函数,必须包含env和start_response的参数(也是服务器里的调用方法)
Python学习者
2023/04/25
8570
【从零学习python 】87. 手动搭建HTTP服务器的Python实现及多线程并发处理
全栈若城
2024/02/29
2130
Python 开发web服务器,socket非堵塞模式
在开发web服务器接受http请求的时候,socket在recv等待接受数据的时候,服务端是堵塞的。 用于等待http发送过来的数据。 那么这个等待,其实也是会占用服务端的资源的。 为了节省这个资源,可以采用非堵塞的方式来进行socket等待监听,就是每次轮询监听一下,并不会堵塞等待。
Devops海洋的渔夫
2019/05/31
1.1K0
Python web框架开发 - WSGI协议
前面我利用TCP协议,返回HTTP数据的方法,实现了web静态页面返回的服务端功能。 但是这样并不能满足大部分的功能需求。
Devops海洋的渔夫
2019/06/02
5190
推荐阅读
相关推荐
Python简单实现Web服务器
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验