Flask基础及常见问题整理

文章介绍了Flask作为Python轻量级web框架的特点,如简单易用、灵活、Pythonic和强大的扩展性。讨论了RESTful协议的核心概念,如基于HTTP、无状态和统一接口。还详细阐述了Flask中的路由注册、Request请求对象和Response响应对象的处理,以及表单处理。最后提到了其他相关知识点,如IP地址、端口、调试模式和参数配置等。
摘要由CSDN通过智能技术生成

一、Flask框架介绍

使用python开发后端,目前主流的框架就是Flask和Django。其中,Flask是一款轻量级的Python web框架,有以下主要特点:

1. 简单易用

Flask很简单易用,可以快速上手开发web应用。它只依赖Werkzeug和Jinja2两个库,没有象Django那样的重量级复杂的功能。

2. 灵活

Flask非常灵活,可以适用于不同的项目规模。从简单的"Hello World"到大型项目都可以使用Flask开发。并且它可以与更多的flask扩展结合,实现更丰富的功能。相对来讲,Django只适合较大的工程。

3. Pythonic

Flask使用Python语言开发,遵循Pythonic的设计理念,语法优雅简洁,具有很强的可读性。这使得Flask非常适合学习和理解。

4. RESTful

Flask天生支持RESTful风格的web服务开发。HTTP一级支持,简单的URL规则等使其非常适合构建REST API。

5. 扩展性强

Flask最重要的一个特点就是拥有丰富的扩展,几乎涵盖了web开发所有的功能,如:ORM(Flask-SQLAlchemy)、表单验证(Flask-WTF)、文件上传(Flask-Uploads)、用户认证(Flask-Login)等。这些扩展可以根据需要很容易集成到Flask应用中。需要什么插件,就安装什么插件。

6. 部署方便

Flask的应用十分简单,甚至一个py文件就行。它支持与各种Web服务器兼容,如WSGI服务器、Nginx和uWSGI等。

7. 社区优秀

Flask拥有庞大的社区,官方文档资料也比较齐全。几乎所有的问题都可以在网上找到答案。

所以,总的来说,Flask是一个简单、灵活、易于理解、可扩展性强的Python web框架。它适用于学习、 小型项目以及复杂项目。具有非常优秀的社区资源和生态环境。

二、RESTFul协议特点

1. 基于HTTP

RESTful API基于HTTP协议,使用HTTP方法为资源定义操作。如GET用于读取,POST用于创建,PUT用于更新,DELETE用于删除等。有的API接口,无论是读取还是更新,都统一使用POST方法,而把实际的动词包含在URL里,如'/data/delete'。

2. 无状态

RESTful API是无状态的,它不存储任何客户端上下文信息。每个请求必须包含请求所需要的所有信息,服务器根据请求进行响应。

3. 层次结构

RESTful API使用统一的接口访问命名空间中的所有资源。这些资源可以被层次化,形成资源的树形结构。

4. 使用URL定位资源

每个资源都有一个唯一的URL来指定和定位,这一点和文件夹路径原理是一样的。

5. 可缓存

RESTful API响应可以是可缓存的,这可以提高效率和性能。缓存可以存在于服务器端、客户端或代理服务器。这一点对于频繁请求某一资源时很有帮助。

6. 统一接口

 RESTful API将所有资源通过统一的接口来访问和操作。这简化了整个系统。

7. 跨语言兼容

RESTful API返回的通常为JSON或XML格式。这使其对各种语言和平台更易于实现和兼容。

REST是一种优秀的开发思路和规范,但我们在实际开发时也要辩证来看。规范和通用的东西必然在灵活性上有所不足。如果我们开发的是对外的、通用的接口,那么REST是一个好的选择。但如果这个接口只对内部提供,则不必严格按照REST协议来。因为实际的业务往往是复杂的、具体的和相对固定的。那么针对性地提供一些接口,会让前端开发(调用者)更容易。某种程度,也可以减少一定的http请求次数。如某个页面有几十个数据需要请求,按照REST风格来可能需要请求几十个接口,而我们可以设计一个统一接口将全部信息返回(有点夸张了)。

三、路由

1、路由的概念

百度百科的解释是:“路由(routing)是指分组从源到目的地时,决定端到端路径的网络范围的进程”。在TCP/IP协议里,路由器的工作就是将不同的信息根据ip地址进行分发。而在web开发中,概念也基本一致。即将前面提到的url与资源进行一种映射,请求相应的url则获取对应资源。而建立这种映射的过程就叫注册路由。

2、两种路由注册方式

from flask import Flask

app = Flask(__name__)


# 方法一
@app.route('/hello')
def hello():
    return 'hello world'


if __name__ == '__main__':
    app.run('0.0.0.0', 5555)

 第一种方法是利用了python装饰器的特性,route方法内部仍然是调用add_url_rule。本质是一样的,只是装饰器看起来更优雅。

关于装饰器的解释可以参考下文Python 装饰器_function databaseerrorwrapper.__call__.<locals>.in_Jiangugu的博客-CSDN博客

from flask import Flask

app = Flask(__name__)


def hello():
    return 'hello world'


# 方法二
app.add_url_rule('/hello', view_func=hello)

if __name__ == '__main__':
    app.run('0.0.0.0', 5555)

                                

四、Request请求对象

以百度搜索关键词python为例,可以通过后台查看请求对象包含的信息

 

可以看到,虽然我们只输入了一个python,但实际的请求包含了很丰富的信息。如请求头里包含的请求地址、方法 ,请求体里包含的关键字等。在一些需要登陆的网站,往往还需要携带cookies。本文主要还是讲解利用flask搭建后端,主要作为响应端。即如何响应请求,关于更多request的介绍请参考下文。

Python 网络开发基础之Requests_request是技术还是库_Jiangugu的博客-CSDN博客

五、Response响应对象

响应对象和请求对象一样,除了“内容”部分,还会包含诸多其他信息。常见的如content-type、status_code。在flask里,必须指定的是内容部分,其余均有默认值。

1、content-type

默认的content-type是html,那么返回的字符串就会按照html的格式去解析,因此前端显示为空。

@app.route('/test')
def test():
    return '<html></html>'

如果想显示这段文本,则手动指定content-type即可

@app.route('/test')
def test():
    header = {
        'content-type': 'text/plain'
    }
    return '<html></html>', header

 

返回一个网页的示例

@web.route('/square/<p>', methods=['GET'])
def square(p):
    """
    :param p:
    :return: 返回的是一个html
    """
    return render_template('test.html', result=int(p)**2)

 这是前端部分(样式CSS和脚本JS没有展开,本文主要讲解后端和接口)。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>'测试网页'</title>
</head>
<body>
<div>
    <p style="color: red">计算结果是:{{ result }}</p>
</div>
</body>
</html>

 

 而对于API来说,content-type为'application/json',即要求调用者按照json格式去解析。

2、状态码

常见状态码包括200(请求成功)、301(重定向)、404(未找到资源)、500(服务器内部错误)。这里需要强调的是,状态码只是一种约定。你完全可以约定请求成功是404,只要事先和请求方约定好。

虽然浏览器报错,但内容仍正常显示。此外,在接口开发中,可能出现的情况会很多。仅有的几个状态码一般都是不够用的。往往会在内容content里再约定一个如status这样的变量,约定1是成功,2是没有权限,3是参数不够,4是数据范围超出……

from flask import Flask
import json
app = Flask(__name__)


@app.route('/test/<nums>')
def test(nums):
    dt = nums.split(',')
    header = {
        'content-type': 'application/json',
    }
    if len(dt) > 10:
        return json.dumps({'status': 4, 'msg': '数据长度不能超过10'}), 500, header
    else:
        return json.dumps({'status': 1, 'result': 111}), 200, header


if __name__ == '__main__':
    app.run('0.0.0.0', port=8000, debug=True)

 

六、表单

除了URL里可以携带参数,还有一种常见的传参方式就是通过表单,如登录和注册页面填写的账号、密码等信息。后端如何接收这些信息呢?

<html>  
	<head>   
		<title>测试网页</title>
		<link rel="stylesheet" type="text/css" href="static/login.css"/>
		<link rel="shortcut icon"
          href="{{ url_for('static', filename='pics/logo.png') }}">
	</head>  
	<body>    
		<div id="main">
			<div id="top">
				<img src={{url_for('static', filename='pics/pure_logo.png')}}  id="logo">
			</div>
			<div id="bottom">
				<form  method="POST">
					<p class="titleofinput">用户名: </p>         
					        
					<input type="text" name="username" class="input" autocomplete="off" placeholder="请输入用户名" required>     
					          
					<p class="titleofinput">密码: </p>         
					         
					<input type="password" name="password" class="input" autocomplete="off" placeholder="请输入密码" required>       
					<br>          
					<button type="submit" id="submit">登录</button>
				</form> 
			</div>
		</div>
	</body>
</html>

这个简单的登录界面示例代码中,输入用户名和密码使用的是<input>标签且存在于<form>里。而它们都有一个name属性,因此后端可以通过这个属性获得对应传递过来的值。

from flask import request, url_for, redirect, render_template
from flask_login import login_user
from model.user import User
from . import web


@web.route('/login', methods=['GET', 'POST'])
def login():
    username = request.form.get('username')
    password = request.form.get('password')
    if request.method == 'POST':
        # 自定义的user模型,将具体的校验方法封装其中,也可以直接粗暴地写在这里
        user = User.query.filter_by(username=username).first()
        if user and user.check_password(password):
            # 将用户登录票据写入客户端cookies, remember开启默认保存365天
            login_user(user, remember=True)
            return redirect(url_for('web.do'))
        else:
            return '用户名或密码错误'

    return render_template('login.html')

七、其他零散知识点

1、IP地址

我们的app在绑定地址时,可以写网卡的实际地址,如192.168.0.111(固定地址,地址改变时需同步更改),也可以写127.0.0.1(只允许本机访问),还可以写0.0.0.0。一般我们在开发的时候,随便写哪个都可以,因为都是本机访问且地址不会变。但如果地址可能会变,同时正式部署后要允许其他计算机访问,就只能写0.0.0.0。

2、端口

原则上,端口可以在1~65535范围内任意指定,只要不与已有的端口冲突即可。如22是ssh通讯端口,3306是数据库端口。而web端口默认是80,即使用默认端口时,浏览器访问可以不指定端口。

3、调试模式

后端开发是一个交互性很强的工作,需要一边调整一边看结果。因此,如果每次修改代码都需要重启应用的话会很浪费时间。在flask里只需要打开调试模式即可实现类似监听的功能,代码的修改能立刻应用。

app.run('0.0.0.0', 8000, debug=True)

4、参数配置

一个优秀的web服务,离不开诸多参数配置。如前面提到的端口号、调试模式等。实际上很多代码工程都需要配置参数,而一个好的参数配置需要具备“可读性强”,“易修改”等特点。因此,最好的方式就是在一个统一的地方,统一对参数进行定义和赋值,在整个工程其他地方使用定义的变量名。这里有两种方式推荐,其一是配置系统环境变量,然后在代码里通过os.environ.get('变量名')。第二种方法是创建一个配置文件,如config.py,在这个文件里配置一些参数,如DEBUG=True,注意变量名需全部大写

# 加载配置模块
app.config.from_object('config')
# 调用相应配置参数
app.run('0.0.0.0',  debug=app.config['DEBUG'])

5、重定向

有一些资源暂时没有或不想让别人访问,除了抛出404,还可以重定向。即建议请求者重新请求一个地址。

@app.route('/test')
def test():
    header = {
        'content-type': 'text/plain',
        'location': 'https://www.baidu.com'
    }
    return '<html></html>', 301, header

6、传参

(1)多参数传参

我们在上面的案例中,参数是直接跟在url后的。那是因为参数只有一个,不太容易引起误解。如果查询参数较多,一般可以使用以下方式

from flask import request
import json


@app.route('/plus')
def plus():
    a = request.args['a']
    b = request.args['b']
    header = {
        'content-type': 'application/json',
    }
    return json.dumps({'status': 1, 'result': int(a) + int(b)}), 200, header

 

(2)数组传参

在调用API接口时,有时会需要传递一个较大的数据。这时候就不适合将数据作为查询参数添加到url里。一方面会导致url可读性较差,同时,url也会有长度限制(因浏览器,服务器等不同,一般限制几千个字符)。此时,可以将数据放到请求体里。

from flask import Flask, request
import json
app = Flask(__name__)


@app.route('/test/')
def test():
    dt = request.json['data']
    header = {
        'content-type': 'application/json',
    }
    if len(dt) > 10:
        return json.dumps({'status': 4, 'msg': '数据长度不能超过10'}), 400, header
    else:
        return json.dumps({'status': 1, 'result': sum(dt)}), 200, header


if __name__ == '__main__':
    app.run('0.0.0.0', port=5555, debug=True)

 7、Cookie

由于http请求是没有记忆的,每次请求都是独立没有上下文关联的。但有时我们需要这种上下文关联,比如记录登录信息、购物网站的购物车、搜索记录等。记录这种信息的载体就是Cookie,它是由服务器生成并写入访问客户端的。客户端在下一次的访问中就会携带该信息,以便继续对话。Cookie是以键值对的形式存储的,除了key-value的信息,一般还包括允许访问的域名、有效期等信息。使用flask框架的服务可以通过以下方式生成Cookie

from flask import make_response

@app.route('/')
def index():
    # 这里快速构造了一个response对象,和前面的一样
    resp = make_response('Hello')
    # 有效期1000秒
    resp.set_cookie('username', 'john', 1000)
    return resp

 访问相应的视图函数,此时浏览器已经被写入Cookie。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值