Flask框架的学习——12—(cookie和session、Flask上下文、常用的钩子函数、Restful API规范、Flask-Restful插件、参数解析、 输出字段、)

1、cookie和session

  1. cookie:在网站中,http请求是无状态的。也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户。cookie的出现就是为了解决这个问题,第一次登录后服务器返回一些数据(cookie)给浏览器,然后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动的把上次请求存储的cookie数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是哪个了。cookie存储的数据量有限,不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用cookie只能存储一些小量的数据。
@app.route('/')
def index():
    # return '123'
    res = Response("首页")
    res.set_cookie('abc', '123', max_age=3)    # key=abc, value=123, 3s后过期
    ''' set_cookie()源码
    def set_cookie(
        self,
        key,
        value="",
        max_age=None,           # 失效时间
        expires=None,           # datetime形式的失效时间
        path="/",               # 在该路径下才能设置cookie
        domain=None,            # 域名限制
        secure=False,           # 仅可通过HTTPS使用
        httponly=False,
        samesite=None,
    ):
    	:param key: the key (name) of the cookie to be set.
        :param value: the value of the cookie.
        :param max_age: should be a number of seconds, or `None` (default) if
                        the cookie should last only as long as the client's
                        browser session.
        :param expires: should be a `datetime` object or UNIX timestamp.
        :param path: limits the cookie to a given path, per default it will
                     span the whole domain.
        :param domain: if you want to set a cross-domain cookie.  For example,
                       ``domain=".example.com"`` will set a cookie that is
                       readable by the domain ``www.example.com``,
                       ``foo.example.com`` etc.  Otherwise, a cookie will only
                       be readable by the domain that set it.
        :param secure: If `True`, the cookie will only be available via HTTPS
    '''
    return res
    

在这里插入图片描述
在这里插入图片描述

  1. session: session和cookie的作用有点类似,都是为了存储用户相关的信息。不同的是,cookie是存储在本地浏览器,session是一个思路、一个概念、一个服务器存储授权信息的解决方案,不同的服务器,不同的框架,不同的语言有不同的实现。虽然实现不一样,但是他们的目的都是服务器为了方便存储数据的。session的出现,是为了解决cookie存储数据不安全的问题的。

  2. cookie和session结合使用:web开发发展至今,cookie和session的使用已经出现了一些非常成熟的方案。在如今的市场或者企业里,一般有两种存储方式:
    存储在服务端:通过cookie存储一个session_id,然后具体的数据则是保存在session中。如果用户已经登录,则服务器会在cookie中保存一个session_id,下次再次请求的时候,会把该session_id携带上来,服务器根据session_id在session库中获取用户的session数据。就能知道该用户到底是谁,以及之前保存的一些状态信息。这种专业术语叫做server side session。存储在服务器的数据会更加的安全,不容易被窃取。但存储在服务器也有一定的弊端,就是会占用服务器的资源,但现在服务器已经发展至今,一些session信息还是绰绰有余的。(Django框架采用这种模式)。
    将session数据加密,然后存储在cookie中:这种专业术语叫做client side session。flask采用的就是这种方式,但是也可以替换成其他形式。

from flask import Flask, session
import os

print(os.urandom(24))    # 输出的是24位随机的字符串  当做secret_key使用

app = Flask(__name__)
# 加密session中的 secret_key
app.config['SECRET_KEY'] = os.urandom(24)


@app.route("/")
def index():
    # session  字典类型
    session['username'] = 'xxx'
    session['user_id'] = 123
    return "1231231"


if __name__ == '__main__':
    app.run(debug=True)

在这里插入图片描述

flask中使用cookie和session

  1. cookies:在Flask中操作cookie,是通过response对象来操作,可以在response返回之前,通过response.set_cookie来设置,这个方法有以下几个参数需要注意:
  • key:设置的cookie的key。
  • value:key对应的value。
  • max_age:改cookie的过期时间,如果不设置,则浏览器关闭后就会自动过期。
  • expires:过期时间,应该是一个datetime类型。
  • domain:该cookie在哪个域名中有效。一般设置子域名,比如cms.example.com。
  • path:该cookie在哪个路径下有效。
  1. session:Flask中的session是通过from flask import session。然后添加值key和value进去即可。并且,Flask中的session机制是将session信息加密,然后存储在cookie中。专业术语叫做client side session。
from flask import Flask, session
import os
from datetime import timedelta    # 导入时间

# print(os.urandom(24))    # 输出的是24位随机的字符串  当做secret_key使用

app = Flask(__name__)
# 加密session中的 secret_key
app.config['SECRET_KEY'] = os.urandom(24)
# 持久化时间设置
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=2)            # 2小时session过期


@app.route("/login/")
def login():
    # session  字典类型     登录操作,记录信息传输到数据库
    session['username'] = 'xxxxxx'
    session['user_id'] = 123
    
    # 持久化  有效期
    session.permanent = True
    
    return "登录界面"


@app.route("/")
def index():
    username = session.get('username')
    print(username)
    return "首页界面"


@app.route("/logout/")
def logout():
    # 删除session中的username
    session.pop('username')
    
    # 清空session中的所有数据
    session.clear()
    
    return "退出登录"


if __name__ == '__main__':
    app.run(debug=True)

2、Flask上下文

Flask项目中有两个上下文,一个是应用上下文(app),另外一个是请求上下文(request)。请求上下文request和应用上下文current_app都是一个全局变量。所有请求都共享的。Flask有特殊的机制可以保证每次请求的数据都是隔离的,即A请求所产生的数据不会影响到B请求。所以可以直接导入request对象,也不会被一些脏数据影响了,并且不需要在每个函数中使用request的时候传入request对象。这两个上下文具体的实现方式和原理可以没必要详细了解。

请求上下文

  • request:请求上下文上的对象。这个对象一般用来保存一些请求的变量。比如method、args、form等。
  • session:请求上下文上的对象。这个对象一般用来保存一些会话信息。

应用上下文

  • current_app:返回当前的app。
  • g:应用上下文上的对象。处理请求时用作临时存储的对象。
    在这里插入图片描述
# -*- encoding: utf-8 -*-
"""
@File    : session_demo.py
@Time    : 2020/5/8 9:57
@Author  : chen

"""
from flask import Flask, session, request, current_app
import os
from datetime import timedelta    # 导入时间
from utils import log_a, log_b       # 导入记录模块

import config


# print(os.urandom(24))    # 输出的是24位随机的字符串  当做secret_key使用

app = Flask(__name__)             # current_app代表app
# 加密session中的 secret_key
app.config['SECRET_KEY'] = os.urandom(24)
# 持久化时间设置
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=2)            # 2小时session过期


@app.route("/login/")
def login():
    # session  字典类型     登录操作,记录信息传输到数据库
    session['username'] = 'xxxxxx'
    session['user_id'] = 123
    
    # 持久化  有效期
    session.permanent = True
    
    return "登录界面"

# 需要在视图函数中调用   不能在视图函数外使用
# print(current_app.name)


@app.route("/")
def index():
    username = session.get('username')
    # 采用g对象,每次刷新页面,会被清空,临时对象
    g.username = username
    log_a()         # 这里可以不用传参   g对象是全局
    log_b()
    
    # print(username)
    print(current_app.name)           # 输出当前app的名字   需要在视图函数中调用

    # 不是读取config.py中的数据,查看的是app绑定的配置
    # print(current_app.config['HOST'])
    print(current_app.config['SECRET_KEY'])    # 输出配置中的数据

    return "首页界面"


@app.route("/logout/")
def logout():
    # 删除session中的username
    session.pop('username')
    
    # 清空session中的所有数据
    session.clear()
    
    return "退出登录"


if __name__ == '__main__':
    app.run(debug=True)
# -*- encoding: utf-8 -*-
"""
@File    : utils.py
@Time    : 2020/5/9 17:18
@Author  : chen

"""
# utils.py 工具文件   发送验证码等,随机生成字符串等

# 记录登录的信息
def log_a(username):
    print("log a %s"% username)


def log_b(username):
    print("log b %s" % username)

g对象的传参

# -*- encoding: utf-8 -*-
"""
@File    : utils.py
@Time    : 2020/5/9 17:18
@Author  : chen

"""
# utils.py 工具文件   发送验证码等,随机生成字符串等

from flask import g           # 导入g对象


# 记录登录的信息
def log_a():
    print("log a %s"% g.username)


def log_b():
    print("log b %s" % g.username)

常用的钩子函数

  • before_first_request:处理第一次请求之前执行。
@app.before_first_request
  def first_request():
      print 'first time request'
  • before_request:在每次请求之前执行。通常可以用这个装饰器来给视图函数增加一些变量。
@app.before_request
  def before_request():
      if not hasattr(g,'user'):
          setattr(g,'user','xxxx')
  • teardown_appcontext:不管是否有异常,注册的函数都会在每次请求之后执行。
@app.teardown_appcontext
def teardown(response):
    print("teardown 被执行")
    return respons
  • context_processor:上下文处理器。返回的字典中的键可以在模板上下文中使用。
@app.context_processor
def context_processor():
    return {'current_user':'xxx'}
  • errorhandler:errorhandler接收状态码,可以自定义返回这种状态码的响应的处理方法。
@app.errorhandler(404)
  def page_not_found(error):
      return 'This page does not exist',404   

钩子函数整体代码文件hook_demo.py

# -*- encoding: utf-8 -*-
"""
@File    : hook_demo.py
@Time    : 2020/5/9 20:27
@Author  : chen

"""
from flask import Flask, render_template, abort

app = Flask(__name__)


@app.route("/")
def index():
    # 主动抛出异常的同时需要errorhandler模块捕获到这个异常
    abort(404)          # 此时访问首页的状态码就是404了,直接运行errorhandler(404)中的方法
    
    # 这种主动抛出异常方式无法被捕获到
    # raise IndexError(" index error!")

    print("这是首页")
    # return "这是首页"
    return render_template("index.html")


# 处理第一次请求之前执行。
@app.before_first_request
def handel_first_request():                  # 只执行一次,刷新后不会再执行
    print("1  这是第一次请求之前执行的")


# before_request:在每次请求之前执行。通常可以用这个装饰器来给视图函数增加一些变量。
@app.before_request
def handel_before_request():
    print("2  每次请求之前执行")
    

# after_request: 在每次请求之后执行
@app.after_request
def handel_after_request(response):
    print("3  每次请求之后执行的")
    return response


#  teardown_appcontext:不管是否有异常,注册的函数都会在每次请求之后执行。
@app.teardown_appcontext
def handel_teardown_appcontext(response):
    print("4  注册的函数都会在每次请求之后执行")
    return response


#  context_processor:上下文处理器。返回的字典中的键可以在模板上下文中使用。
@app.context_processor
def handel_context_processor():
    print("5 上下文处理器。返回的字典中的键可以在模板上下文中使用。")
    return {"username": "abcd"}              # 将这个参数变量映射到模板html文件中,


# 错误异常的捕获
#  errorhandler:errorhandler接收状态码,可以自定义返回这种状态码的响应的处理方法。
@app.errorhandler(404)
def handel_errorhandler(error):           # error必须传递
    print("6 errorhandler接收状态码,可以自定义返回这种状态码的响应的处理方法。")
    # return "页面不存在", 404                    # 404网页访问状态码
    return render_template("404.html"), 404      # 404网页访问状态码


@app.errorhandler(500)
def server_error(error):           # error必须传递
    return "服务器错误!", 500      # 500 网页响应状态码

    
if __name__ == '__main__':
    # 项目上线之后 部署到服务器,debug模式需要关闭,因为报错信息不能给客户看
    app.run(debug=True, port=9999)

404.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p>页面不见了!!!!</p>
</body>
</html>

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--   使用context_processor:上下文处理器进行参数传递 -->
    {{  username }}

</body>
</html>

3、Restful API规范

restful api是用于在前端与后台进行通信的一套规范。使用这个规范可以让前后端开发变得更加轻松。以下将讨论这套规范的一些设计细节。

协议
采用http或者https协议。

数据传输格式
数据之间传输的格式应该都使用json,而不使用xml。

url链接
url链接中,不能有动词,只能有名词。并且对于一些名词,如果出现复数,那么应该在后面加s。

HTTP请求的方法

  • GET:从服务器上获取资源。
  • POST:在服务器上新创建一个资源。
  • PUT:在服务器上更新资源。(客户端提供所有改变后的数据)
  • PATCH:在服务器上更新资源。(客户端只提供需要改变的属性)
  • DELETE:从服务器上删除资源。

示例:

  1. GET /users/:获取所有用户。
  2. POST /user/:新建一个用户。
  3. GET /user/id/:根据id获取一个用户。
  4. PUT /user/id/:更新某个id的用户的信息(需要提供用户的所有信息)。
  5. PATCH /user/id/:更新某个id的用户信息(只需要提供需要改变的信息)。
  6. DELETE /user/id/:删除一个用户。

在这里插入图片描述

4、Flask-Restful插件

Flask-Restful是一个专门用来写restful api的一个插件。使用他可以快速的集成restful api功能。在app的后台以及纯api的后台中,这个插件可以帮助我们节省很多时间。当然,如果在普通的网站中,这个插件就显得有些鸡肋了,因为在普通的网页开发中,是需要去渲染HTML代码的,而Flask-Restful在每个请求中都是返回json格式的数据。

安装
Flask-Restful需要在Flask 0.8以上的版本,在Python2.6或者Python3.3上运行。通过pip install flask-restful即可安装。
在这里插入图片描述

定义Restful的视图
如果使用Flask-Restful,那么定义视图函数的时候,就要继承自flask_restful.Resource类,然后再根据当前请求的method来定义相应的方法。比如期望客户端是使用get方法发送过来的请求,那么就定义一个get方法。类似于MethodView。

from flask import Flask,render_template,url_for
from flask_restful import Api, Resource

app = Flask(__name__)
# 用Api来绑定app
api = Api(app)


class IndexView(Resource):    # 类视图不同于之前继承View
    def get(self):
        return {"username":"xxx"}         # 返回数据
    
    def post(self):
        return {"info": "登陆成功"}


api.add_resource(IndexView, '/', endpoint='index')         # 类视图绑定

if __name__ == '__main__':
    app.run(debug=True)

注意事项

  • endpoint是用来给url_for反转url的时候指定的。如果不写endpoint,那么将会使用视图的名字的小写来作为endpoint。
  • add_resource的第二个参数是访问这个视图函数的url,这个url可以跟之前的route一样,可以传递参数。并且还有一点不同的是,这个方法可以传递多个url来指定这个视图函数。

在这里插入图片描述
Postman软件测试post方法传递参数是否连接成功
在这里插入图片描述

5、 参数解析

Flask-Restful插件提供了类似WTForms来验证提交的数据是否合法的包,叫做reqparse。

在这里插入图片描述
add_argument可以指定这个字段的名字,这个字段的数据类型等。

  • default:默认值,如果这个参数没有值,那么将使用这个参数指定的值。
  • required:是否必须。默认为False,如果设置为True,那么这个参数就必须提交上来。
  • type:这个参数的数据类型,如果指定,那么将使用指定的数据类型来强制转换提交上来的值。
  • choices:选项。提交上来的值只有满足这个选项中的值才符合验证通过,否则验证不通过。
  • help:错误信息。如果验证失败后,将会使用这个参数指定的值作为错误信息。
  • trim:是否要去掉前后的空格。
from flask import Flask, render_template, url_for
from flask_restful import Api, Resource, reqparse, inputs   # reqparse 类似WTForms来验证提交的数据是否合法 ,inputs验证email,url等数据

app = Flask(__name__)
# 用Api来绑定app
api = Api(app)


class IndexView(Resource):  # 类视图不同于之前继承View
    def get(self):
        return {"username": "xxx"}  # 返回数据
    
    def post(self):
        # 类似WTForms来验证提交的数据是否合法
        parse = reqparse.RequestParser()
        # 传参     help=错误信息     required=True必须提供该参数
        parse.add_argument('username', type=str, help='用户名验证错误', required=True)
        parse.add_argument('password', type=str, help='用户名密码错误', required=True)
        parse.add_argument('age', type=int, help='用户年龄错误')
        parse.add_argument('gender', type=str, help='用户性别错误', choices=['male', 'female'])
        
        # url验证\邮箱验证
        parse.add_argument('homepage', type=inputs.url, help='网页链接错误', required=True)
        # regex  正则表达式   手机号码验证
        parse.add_argument('phone', type=inputs.regex(r'1[3456]\d{9}'), help='手机号码错误', required=True)

        # 验证参数是否传递成功
        args = parse.parse_args()
        print(args)
        
        return {"info": "登陆成功"}


api.add_resource(IndexView, '/', endpoint='index')  # 类视图绑定

if __name__ == '__main__':
    app.run(debug=True)

6、 输出字段

对于一个视图函数,你可以指定好一些字段用于返回。以后可以使用ORM模型或者自定义的模型的时候,他会自动的获取模型中的相应的字段,生成json数据,然后再返回给客户端。这其中需要导入flask_restful.marshal_with装饰器。并且需要写一个字典,来指示需要返回的字段,以及该字段的数据类型。

from flask import Flask, render_template, url_for
from flask_restful import Api, Resource, reqparse, inputs  # reqparse 类似WTForms来验证提交的数据是否合法 ,inputs验证email,url等数据
from flask_restful import fields, marshal_with      # fields用于输出字段   marshal_with装饰器关联返回字段信息
app = Flask(__name__)
# 用Api来绑定app
api = Api(app)


class ArticleView(Resource):      # 类视图不同于之前继承View,这里需要继承Resource
    resource_fields = {           # 返回字段信息
        'title': fields.String,
        'content': fields.String,
    }
    
    @marshal_with(resource_fields)         # 关联返回字段信息
    def get(self):
        return {'title': 'abcdefg'}


api.add_resource(ArticleView, '/article/', endpoint='article')  # 类视图绑定

if __name__ == '__main__':
    app.run(debug=True)

在这里插入图片描述

重命名属性
很多时候你面向公众的字段名称是不同于内部的属性名。使用 attribute可以配置这种映射。比如现在想要返回user.school中的值,但是在返回给外面的时候,想以education返回回去,那么可以这样写

resource_fields = {
    'education': fields.String(attribute='school')
}

默认值
在返回一些字段的时候,有时候可能没有值,那么这时候可以在指定fields的时候给定一个默认值

resource_fields = {
    'age': fields.Integer(default=18)
}

复杂结构
有时候想要在返回的数据格式中,形成比较复杂的结构。那么可以使用一些特殊的字段来实现。比如要在一个字段中放置一个列表,那么可以使用fields.List,比如在一个字段下面又是一个字典,那么可以使用fields.Nested。

class ProfileView(Resource):
    resource_fields = {
        'username': fields.String,
        'age': fields.Integer,
        'school': fields.String,
        'tags': fields.List(fields.String),
        'more': fields.Nested({
            'signature': fields.String
        })
    }

实例代码如下

主体代码文件: flask_restful_demo1.py

from flask import Flask, render_template, url_for
from flask_restful import Api, Resource, reqparse, inputs  # reqparse 类似WTForms来验证提交的数据是否合法 ,inputs验证email,url等数据
from flask_restful import fields, marshal_with  # fields用于输出字段   marshal_with装饰器关联返回字段信息

import config    # 导入配置文件
from exts import db      # 第三方文件防止互相引用

from model import Article    # 导入模型

app = Flask(__name__)

# 加载配置
app.config.from_object(config)
db.init_app(app)                      # 绑定app

# 用Api来绑定app
api = Api(app)


class ArticleView(Resource):  # 类视图不同于之前继承View,这里需要继承Resource
    resource_fields = {  # 返回字段信息
        # 'title': fields.String,
        # 修改给前端返回的字段信息   原本的模型中的属性或者叫字段为title,现在返回给前端的是article_title
        'article_title': fields.String(attribute='title'),
        
        'content': fields.String,
        # 'author': fields.String,
        'author': fields.Nested({               # 一对多关系
            "username": fields.String,
            "email": fields.String,
        }),
        
        # 'tag': fields.String,
        'tag': fields.List(fields.Nested({      # 多对多关系
            "id": fields.Integer,
            "name": fields.String,
        })),

        # 模型中没有的字段名和设置默认值
        'read_count': fields.Integer(default=0)
    }
    
    @marshal_with(resource_fields)  # 关联返回字段信息
    def get(self, article_id):       # 传参
        article = Article.query.get(article_id)
        return article                  # 返回模型,返回的数据中包含模型中的所有字段
        # return {'title': 'abcdefg'}


api.add_resource(IndexView, '/', endpoint='index')  # 类视图绑定
# api.add_resource(ArticleView, '/article/', endpoint='article')  # 类视图绑定
api.add_resource(ArticleView, '/article/<article_id>', endpoint='article')  # 传参的时候路由也一起改变


if __name__ == '__main__':
    app.run(debug=True)

模型文件model.py

# -*- encoding: utf-8 -*-
"""
@File    : model.py
@Time    : 2020/5/10 17:09
@Author  : chen

"""
from exts import db

# 用户
# 文章         用户与文章是一对多关系
# 标签         文章与标签是多对多关系     此时需要建立中间表
class User(db.Model):
    __tablename__ = 'user'
    
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(50))
    email = db.Column(db.String(50))


# 中间表的创建   创建article和tag的中间表
article_tag_table = db.Table(
    'article_tag',
    db.Column('article_id', db.Integer, db.ForeignKey('article.id')),
    db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')),
)


class Article(db.Model):
    __tablename__ = 'article'
    
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(50))
    context = db.Column(db.String(50))
    
    # 外键
    author_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    # 反向引用
    author = db.relationship('User', backref='articles')
    
    # 中间表建立连接关系
    tags = db.relationship('Tag', secondary=article_tag_table, backref='tags')
    

class Tag(db.Model):
    __tablename__ = 'tag'
    
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))    

配置文件config.py

# -*- encoding: utf-8 -*-
"""
@File    : config.py
@Time    : 2020/5/10 17:08
@Author  : chen

"""
HOSTNAME = '127.0.0.1'
DATABASE = 'demo0510'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'

DB_URL = 'mysql+mysqlconnector://{}:{}@{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

# engine = create_engine(DB_URL)
SQLALCHEMY_DATABASE_URI = DB_URL
SQLALCHEMY_TRACK_MODIFICATIONS = False

第三方引用文件exts.py :防止互相引用报错

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

映射到数据库文件manage.py

# -*- encoding: utf-8 -*-
"""
@File    : manage.py
@Time    : 2020/5/10 17:36
@Author  : chen

"""
from flask_script import Manager
from flask_restful_demo import app     # 需要将当前文件夹设置为当前根目录,才不会报错
from flask_migrate import Migrate, MigrateCommand
from exts import db

# 导入模型 才能映射到数据库
import model

manage = Manager(app)

Migrate(app, db)
manage.add_command('db', MigrateCommand)

if __name__ == '__main__':
    manage.run()

在这里插入图片描述

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是使用 Flask-RESTfulFlask-SocketIO 构建前后端分离的聊天程序的示例代码: 后端代码: ```python from flask import Flask, request from flask_restful import Resource, Api from flask_cors import CORS from flask_socketio import SocketIO, send, emit app = Flask(__name__) api = Api(app) CORS(app) socketio = SocketIO(app, cors_allowed_origins='*') class Chat(Resource): def get(self): return {'message': 'Welcome to the chat app!'} def post(self): data = request.get_json() message = data['message'] emit('message', message, broadcast=True) return {'message': message} api.add_resource(Chat, '/chat') if __name__ == '__main__': socketio.run(app, debug=True) ``` 前端代码: ```html <!DOCTYPE html> <html> <head> <title>Chat App</title> </head> <body> <h1>Chat App</h1> <div id="messages"></div> <form> <input id="message" type="text"> <button type="submit" id="send">Send</button> </form> <script src="https://cdn.socket.io/socket.io-3.1.0.min.js"></script> <script> const socket = io('http://localhost:5000'); socket.on('message', function (data) { const messages = document.getElementById('messages'); messages.innerHTML += '<p>' + data + '</p>'; }); const form = document.querySelector('form'); form.addEventListener('submit', function (event) { event.preventDefault(); const input = document.getElementById('message'); const message = input.value; socket.emit('message', message); input.value = ''; }); </script> </body> </html> ``` 在这个示例中,我们创建了一个名为 Chat 的资源,其中 GET 请求将返回欢迎消息,而 POST 请求将广播收到的消息。我们使用 Flask-SocketIO 在后端处理 WebSocket 连接,并使用 emit 函数将消息发送给所有连接的客户端。前端代码使用 Socket.IO 客户端库来建立 WebSocket 连接,并使用 emit 函数将用户输入的消息发送到服务器。收到服务器发送的消息时,前端代码将其显示在页面上。 要运行此示例,请确保已安装 FlaskFlask-RESTfulFlask-Cors 和 Flask-SocketIO,并在终端中运行以下命令: ``` $ export FLASK_APP=app.py $ flask run ``` 然后在浏览器中打开 http://localhost:5000/,即可开始聊天。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值