Python一天一道面试题-自写简单版flask框架

什么是flask框架?

Flask是一种基于Python编程语言的轻量级Web应用程序框架。它提供了一个简单易用的方式来构建Web应用程序,具有灵活性和可扩展性。

Flask框架的主要作用是帮助开发人员构建Web应用程序,并提供许多常见的Web开发功能,如路由、模板引擎、请求和响应处理、会话管理等。使用Flask框架,开发人员可以快速创建Web应用程序并将其部署到生产环境中。

Flask框架还支持许多扩展,例如ORM(对象关系映射器)和表单验证,使得开发人员能够更加高效地开发Web应用程序。此外,Flask框架也非常适合构建REST API和微服务等互联网应用程序。

flask框架使用的demo


# 如果我们的pycharm是社区版,需要先安装flask框架

# 安装命令 pip install flask

import flask


app = flask.Flask(__name__)



@app.route('/report')

def report():

return "报告页面"



@app.route('/login')

def login():

return "登录页面"



@app.route('/register')

def register():

return "注册页面"



if __name__ == '__main__':

app.run()

执行上面代码,会在控制台弹出本地的访问地址,将其复制到网页中进行访问。

代码执行

页面访问信息

自己写一个类似的flask框,来了解flask执行原理

在自己编写一个简单的flask框架前,我们要知道flask框架的原理是什么?下面将简单的讲述一下flask的执行原理。

1.接收请求:

Flask框架通过HTTP服务器(如Gunicorn、uWSGI等)监听指定的端口,当有请求到达时,框架接收并处理该请求。

2.路由匹配:

Flask框架根据请求的URL路径,通过定义的路由规则进行匹配,确定要执行的视图函数(处理请求的函数)。

3.视图函数执行:

一旦匹配到对应的路由,Flask框架会调用与该路由关联的视图函数。视图函数处理请求并返回相应的数据。

4.请求上下文管理:

在执行视图函数之前,Flask框架会为每个请求创建一个请求上下文对象,该对象包含请求的相关信息(如请求头、请求参数等)。请求上下文对象会被绑定到当前线程,以便在视图函数中访问请求的信息。

5.视图函数返回:

视图函数执行完毕后,会返回一个响应对象,其中包含要返回给客户端的数据(如HTML内容、JSON数据等)。

6.响应处理:

Flask框架将响应对象处理成符合HTTP协议的格式,包括设置响应头信息、序列化响应数据等。

7.响应发送:

最后,Flask框架将响应发送给HTTP服务器,由服务器将响应返回给客户端。

总结一下简单来说,就是要接收的http请求进行处理判断,然后再根据自己定义的规则进行数据的返回。

编写flask框架服务器

在编写flask框架服务器前,我们要知道HTTP协议的底层使用的是基于TCP/IP协议的套接字(socket)进行通信。HTTP是一种应用层协议,而TCP/IP是一组网络通信协议,其中TCP(Transmission Control Protocol)是一种可靠的、面向连接的协议,提供数据传输的可靠性和顺序性。HTTP利用TCP/IP协议的可靠性和连接性进行数据传输,通过建立和维护套接字连接,进行请求和响应的交换。因此,HTTP协议可以看作是在TCP/IP协议之上构建的一种应用层协议,使用套接字作为底层通信机制。

所以flask框架服务器的代码实现时,其实也是可以直接继承socket通信框架来实现,不过在这,我就直接编写HttpServer服务器代码了,就不再去写socket服务器代码再去继承了。


class HttpServer:

def __init__(self):

# 创建一个流式套接字

self.sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)

# 绑定端口和地址

self.sock.bind(('127.0.0.1', 9988))

# 设置监听

self.sock.listen(20)

self.routers = {}


def run(self, thread=1):

print("服务已启动,运行在本地:127.0.0.1:9988")

# 创建线程池,可以多线程执行

with ThreadPoolExecutor(max_workers=thread) as tp:

while True:

# 4、等待客户端连接

client_socket, addr = self.sock.accept()

# 将处理函数提交到线程池去处理

tp.submit(self.handle_request, client_socket, addr)


def handle_request(self, client_socket, addr):

"""处理http请求"""

print("客户端{}建立连接".format(addr))

# 1、接收请求数据报文

data = self.recv_data(client_socket)

# 2、解析http请求

request = self.parser_request_data(data)

# 3、处理请求

res = self.match_handle_method(request)

# 4、返回http报文

self.return_response(client_socket, res['status'], res['body'])

# 5、断开连接

client_socket.close()


def recv_data(self, client_socket):

"""接收请求数据"""

data = b''

while True:

# 接收客户端传递过来的数据

r = client_socket.recv(1024)

data += r

if len(r) < 1024:

break

# 返回字符串

return data.decode()


def parser_request_data(self, data):

"""解析http请求"""


# 请求方法

method = data.split('\r\n')[0].split(' ')[0]

# 请求路径

path = data.split('\r\n')[0].split(' ')[1]

# 请求头

head = data.split('\r\n\r\n')[0].split('\r\n')[1:]

headers = {i.split(':')[0]: i.split(':')[1] for i in head}

# 请求参数

query_params = {}

json_params = {}

form_params = {}

if "?" in path:

path, query_str = path.split('?')

query_params = {i.split('=')[0]: i.split('=')[1] for i in query_str.split('&')}

# 请求体参数,json格式,表单

if headers.get('Content-Type') == " application/json":

json_params = json.loads(data.split('\r\n\r\n')[1])

elif headers.get("Content-Type") == " application/x-www-form-urlencoded":

form_str = data.split('\r\n\r\n')[1]

form_params = {i.split('=')[0]: i.split('=')[1] for i in form_str.split('&')}

res = {

"method": method,

"path": path,

"headers": headers,

"params": query_params,

"data": form_params,

"json": json_params

}

return res


def return_response(self, client_socket, status=200, body=''):

"""返回http报文"""

HTTPCODE = {

200: 'HTTP/1.1 200 OK\r\n',

404: 'HTTP/1.1 400 NOT FOUND\r\n'

}

header = HTTPCODE.get(status)

header += "Content-Type:text/html;charset=utf-8\r\n"

header += "\r\n\r\n"

if isinstance(body, bytes):

response = header.encode() + body

else:

response = header.encode() + body.encode()

client_socket.send(response)


def match_handle_method(self, request):

"""匹配请求处理方法处理请求,返回要返回给客户端的内容"""

if self.routers.get(request['path']):

handle_method = self.routers.get(request['path'])

status = 200

# 调用处理函数

body = handle_method()

else:

status = 404

body = '页面不存在'

return {

"status": status,

"body": body

}


# 路由装饰器

def route(self, path):

def wrapper(func):

self.routers[path] = func


return wrapper

编写路由信息

在上面我们已经编写好了HttpServer服务器的代码,现在我们可以和上面flask框架demo一样写几个路由(网页访问地址)来测试一下我们自己的HttpServer服务器代码的正确性。


from day7.HttpServer1 import HttpServer


# 实例化HttpServer对象

app = HttpServer()



@app.route("/login")

def login():

return "这是登录页面"



@app.route("/register")

def register():

return "这是注册页面"



@app.route("/")

def index():

return "这是首页"



if __name__ == '__main__':

app.run()

代码执行后显示

接着我们可以发送一个请求来看一下HttpSerer的返回结果情况。


import socket


# 创建一个流式套接字

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 连接地址

client.connect(('127.0.0.1', 9988))

# 设置发送的请求信息

request_data = 'GET /login HTTP/1.1\r\nHost: 127.0.0.1:9988\r\n\r\n'

# 发送请求信息

client.send(request_data.encode())

# 接收服务器返回的响应信息

response_data = client.recv(1024).decode()

print("服务器返回结果:", response_data)

# 关闭socket连接

client.close()

发送请求后,服务器返回给我们的结果,从返回的响应结果中我们就可以看到这和flask框架的执行原理是类似的,这样一来就能证明我们的简单版flask框架就完成了。

总结

其实在实际测试开发学习中,我们不用自己去编写一个HttpServer服务器来用,我们可以直接使用现成的第三方Python库就好了,毕竟其功能完善程度肯定是比我们自己写的好很多。那为什么我这边还要再介绍、自己写一遍简单的flask框架呢?

其实道理很简单,我们一直听说或者使用flask框架,但是自己却不真正的了解其底层代码实现的原理,只是知道有这么个东西,用起来也是一知半解的。如果我们自己能简单的写一下其执行原理的代码,就能更好的了解我们使用的工具,也能更好的去进行测试开发的学习和以后框架的设计。

行动吧,在路上总比一直观望的要好,未来的你肯定会感 谢现在拼搏的自己!如果想学习提升找不到资料,没人答疑解惑时,请及时加入扣群: 320231853,里面有各种软件测试+开发资料和技术可以一起交流学习哦。

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!

  • 19
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值