使用Flask编写Python后端接口,实现服务端提供接口并处理JSON数据和数组

文章目录

  • 一、Flask 构成
  • 二、基于flask写后端接口
  • 2.1、接口可以调用其他类成员示例
  • 2.2、接口的入参是多个的示例
  • 2.3、接口的入参是路径的示例
  • 2.4、接口的入参是数组的示例
  • 2.5、python接收json数据或数组
  • 2.5.1、接口的入参是list的示例,入参是json格式
  • 2.5.2、接收json数据
  • 2.5.3、接收list数据并以list json输出
  • 2.6、将本地文件转化为接口的形式让前端访问
  • 三、跨域设置
  • 四、接收数据的方式以及请求
  • 方式一:放文件路径上
  • 方式二:form data
  • 五、如果后端返回的数据前端接收不到
  • 六、调用说明
  • 七、返回中文编码问题
  • Flask 是一个基于 Python 的轻量级 Web 框架,用于构建 Web 应用程序和 RESTful API。它被设计为简单、易用、灵活,并且具有良好的扩展性。Flask 是一个微型框架,提供了一些基本功能,但也允许开发者根据需要选择并添加扩展。

    一、Flask 构成

    1. 路由(Routing):Flask 使用路由来定义 URL 和对应的处理函数。通过装饰器 @app.route(),可以将一个 URL 映射到相应的处理函数上,从而实现请求的路由和处理。

    2. 视图函数(View Functions):视图函数是 Flask 中处理请求的核心组件,它接收请求并返回响应。视图函数通常被装饰器绑定到特定的 URL 路由上。

    3. 请求上下文(Request Context):Flask 在处理请求时会创建一个请求上下文,其中包含了请求的信息,例如请求的方法、URL 参数、表单数据等。视图函数可以通过 request 对象来访问请求上下文中的数据。

    4. 响应对象(Response Object):视图函数需要返回一个响应对象,用于向客户端返回数据。Flask 提供了 make_response() 函数和 Response 类来构造响应对象,也可以直接返回字符串、模板渲染结果等。

    5. 模板引擎(Template Engine):Flask 默认使用 Jinja2 模板引擎来渲染 HTML 页面。模板引擎允许开发者在模板中嵌入动态内容,从而将数据和视图分离,使页面更加灵活和易于维护。

    6. 上下文全局变量(Context Globals):Flask 提供了一些上下文全局变量,例如 current_appg,可以在视图函数中使用。current_app 表示当前应用的实例,g 是一个全局变量字典,可以在同一请求中共享数据。

    7. 扩展(Extensions):Flask 的功能可以通过扩展来增强,例如数据库支持、表单验证、用户认证等。Flask 社区提供了大量的扩展,使开发者能够更方便地添加功能。

    8. 蓝图(Blueprint):蓝图是一种将 Flask 应用分割为小模块的方式,可以将相关的路由和视图函数组织在一个蓝图中,使应用更加结构化和易于管理。

    示例如下:

    from flask import Flask, request, jsonify
     
    # 用当前脚本名称实例化Flask对象,方便flask从该脚本文件中获取需要的内容
    app = Flask(__name__)
     
    #在Flask中,路由是通过@app.route装饰器(以@开头)来表示
    @app.route("/")
    def index():
        return "Hello World!"
     
    #methods参数用于指定允许的请求格式,#常规输入url的访问就是get方法
    @app.route("/hello",methods=['GET','POST'])
    def hello():
        return "Hello World!"
     
    #注意路由路径不要重名,映射的视图函数也不要重名
    @app.route("/hi",methods=['POST'])
    def hi():
        return "Hi World!"
     
     
    #指定参数
        #string 接受任何不包含斜杠的文本
        #int 接受正整数
        #float 接受正浮点数
        #path 接受包含斜杠的文本
     
    @app.route("/index/<int:id>",)
    def index_args(id):
        if id == 1:
            return 'first'
        elif id == 2:
            return 'second'
        elif id == 3:
            return 'thrid'
        else:
            return 'hello world!'
     
     
    #request对象的使用
    @app.route("/index/request",)
    def index_request():
        if request.method == 'GET':
            return render_template('index.html')
        elif request.method == 'POST':
            name = request.form.get('name')
            password = request.form.get('password')
            return name+" "+password
     
     
    #请求钩子before_request/after_request
    #想要在正常执行的代码的前、中、后时期,强行执行一段我们想要执行的功能代码,便要用到钩子函数---用特#定装饰器装饰的函数。
    @app.before_request
    def before_request_a():
        print('I am in before_request_a')
     
    @app.before_request
    def before_request_b():
        print('I am in before_request_b')
     
     
     
    #before_first_request:与before_request的区别是,只在第一次请求之前调用;
     
     
    #after_request:每一次请求之后都会调用;
    #teardown_request:每一次请求之后都会调用;
     
    #after_request、teardown_request 钩子函数表示每一次请求之后,可以执行某个特定功能的函数,这个函数接收response对象,所以执行完后必须归还response对象;
    #执行的顺序是先绑定的后执行;
     
    @app.after_request
    def after_request_a(response):
        print('I am in after_request_a')
        # 该装饰器接收response参数,运行完必须归还response,不然程序报错
        return response
     
     
    #redirect重定向,应该配合url_for函数来使用
    @app.route('/redirect_index')
    def index():
        # redirect重定位(服务器向外部发起一个请求跳转)到一个url界面;
        # url_for给指定的函数构造 URL;
        # return redirect('/hello') 不建议这样做,将界面限死了,应该如下写法
        return redirect(url_for('hello'))
     
     
    #返回json数据给前端
    @app.route("/web_index")
    def index():
       data = {
           'name':'张三'
       }
       return jsonify(data)
     
    # 启动http服务
    if __name__ == '__main__':
        app.run()#默认端口5000
        #app.run(debug=True,port=8999) 自定义端口为8999      
    

    二、基于flask写后端接口

    2.1、接口可以调用其他类成员示例

    from flask import Flask
    
    app = Flask(__name__)
    
    class Database:
        def __init__(self):
            self.data = []
    
        def add_item(self, item):
            self.data.append(item)
    
        def get_items(self):
            return self.data
    
    db = Database()
    
    @app.route('/api/add_item/<item>', methods=['POST'])
    def add_item(item):
        db.add_item(item)
        return 'Item added successfully.'
    
    @app.route('/api/get_items', methods=['GET'])
    def get_items():
        items = db.get_items()
        return ', '.join(items)
    
    @app.route('/post/<int:post_id>')
    def show_post(post_id):
        return 'post_id: %d' % post_id
    
    @app.route('/login', methods=['GET', 'POST'])
    def login():
        if request.method == 'POST':
            print('request',request)
            return 'POST'
    
        if request.method == 'GET':
            return 'GET'
    
    if __name__ == '__main__':
        app.run(debug=True)#端口默认为5000
        #app.run(debug=True,port=8999) 自定义端口为8999
    

    app.route装饰器用于将URL规则和视图函数绑定。app.run方法启动了开发服务器,并且debug=True参数启用了调试模式,方便开发过程中进行代码更新和调试。flask接口默认端口为5000,也可以自定义端口。

    2.2、接口的入参是多个的示例

    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/api/user/<username>/profile/<int:age>', methods=['GET'])
    def get_user_profile(username, age):
        # 使用username和age进行相关操作
        return 'Username: {}, Age: {}'.format(username, age)
    
    if __name__ == '__main__':
        app.run(debug=True)
    

    2.3、接口的入参是路径的示例

    from flask import Flask, request
    
    app = Flask(__name__)
    
    @app.route('/api/user', methods=['GET'])
    def get_user():
        path = request.args.get('path')
        # 使用path进行相关操作
        return 'Path: {}'.format(path)
    
    if __name__ == '__main__':
        app.run(debug=True)
    

    调用方法:

    curl -X GET "http://localhost:5000/api/user?path=/your/path"
    

    2.4、接口的入参是数组的示例

    from flask import Flask, request
    
    app = Flask(__name__)
    
    @app.route('/api/user', methods=['GET'])
    def get_user():
        ids = request.args.getlist('ids')
        # 使用ids数组进行相关操作
        return 'IDs: {}'.format(ids)
    
    if __name__ == '__main__':
        app.run(debug=True)
    

    调用方法:

    curl -X GET "http://localhost:5000/api/user?ids=1&ids=2&ids=3"
    
    

    2.5、python接收json数据或数组

    2.5.1、接口的入参是list的示例,入参是json格式

    from flask import Flask, request, jsonify
    
    app = Flask(__name__)
    
    @app.route('/process_data', methods=['POST'])
    def process_data():
        # 从请求中获取 JSON 数据
        request_data = request.json
        
        # 假设请求数据是一个包含数字的列表
        data_list = request_data.get('data', [])
        
        # 对列表中的数据进行加倍处理
        doubled_data = [x * 2 for x in data_list]
        
        # 返回处理后的数据   使用jsonify来讲定义好的数据转换成json格式,并且返回给前端
        response_data = {'doubled_data': doubled_data}
        return jsonify(response_data)
    
    if __name__ == '__main__':
        app.run(debug=True)
    
    

    调用方法:

    curl -H "Content-Type: application/json" -H "Data_Type:msg" -X POST -d '{"data":[1, 2, 3, 4, 5]}' http://localhost:5000/process_data
    

    响应:

    {
        "doubled_data": [2, 4, 6, 8, 10]
    }
    

    2.5.2、接收json数据

    # post XML 输入格式 {"bl_code": "BLA123P013", "ua_code": "UAA123P008"}
    @app.route('/mes/api/v1.0/postxml', methods=['POST', 'OPTIONS', 'GET'])
    def comm_postxml():
     
        # bl_code 和 ua_code 允许用户自行输入,用户传入 bl_code和ua_code值
        searchlists = request.get_json()
        print(searchlists)
        bl_code = searchlists['bl_code']
        ua_code = searchlists['ua_code']
        print(bl_code, ua_code)
    

    输出如下

    {'bl_code': 'BLA123P014', 'ua_code': 'UAA123P014'}
    BLA123P014 UAA123P014
    

    或者换一种写法

    # post XML 输入格式 {"bl_code": "BLA123P013", "ua_code": "UAA123P008"}
    @app.route('/mes/api/v1.0/postxml', methods=['POST', 'OPTIONS', 'GET'])
    def comm_postxml():
     
        # bl_code 和 ua_code 允许用户自行输入,用户传入 bl_code和ua_code值
        bl_code = request.json['bl_code']
        ua_code = request.json['ua_code']
        print(bl_code, ua_code)
    

    2.5.3、接收list数据并以list json输出

    @app.route('/mes/api/v1.0/get_dpcapacklists', methods=['POST', 'OPTIONS', 'GET'])
    def get__dpcapacklists():
        print(request)
        print("print serarchlists")
        packageList = request.get_json()
     
        print(packageList)
        print(packageList[0])
        print(packageList[0]["moduleList"])
        print(len(packageList[0]["moduleList"]))
     
        print(packageList[0]["moduleList"][0])
        print("=====================================")
        print(packageList[0]["moduleList"][0]['moduleCode'])
        print("=====================================")
        print(packageList[0]["moduleList"][0]["cellList"])
        print("=====================================")
        print(packageList[0]["moduleList"][0]["cellList"][0])
     
        return jsonify({'list': packageList})
    

    或者只返回部分字段作为list

    @app.route('/mes/api/v1.0/get_dpcapacknums', methods=['POST', 'OPTIONS', 'GET'])
    def get_dpcapacknums():
        print("======================getccccccccccccccccccccccccccccccccccccccccapsapacklist post")
        print(request)
        print("print serarchlists")
        packageList = request.get_json()
        print(len(packageList))
        packlist = []
        i = 0
        for i in range(len(packageList)):
            print(packageList[i]['global_pack_code'])
            packlist.append(packageList[i]['global_pack_code'])
        return jsonify({'list': packlist})#返回pack号码
    

    2.6、将本地文件转化为接口的形式让前端访问

    from flask import Flask, request, send_file
    
    app = Flask(__name__)
    
    
    @app.route('/download/<filename>')
    def download_file(filename):
        if filename == 'pdf':
            return  send_file('国土云举证图片示例.pdf')
        if filename == 'txt':
         return send_file('test.txt')
    
    
    if __name__ == "__main__":
        app.run(host='0.0.0.0', port=5000)
    

    三、跨域设置

    当你的后端服务启动并监听指定的端口后,如果前端无法调用后端服务,可能有以下几个原因:

    1. 网络连接问题:确保前端应用能够访问后端服务所在的服务器。检查服务器的网络配置、防火墙设置等,并确保前端应用能够正确访问服务器的IP地址和端口。

    2. 跨域资源共享(CORS)问题:如果前端应用和后端服务不在同一个域名下(例如,前端应用在http://localhost:3000,后端服务在http://localhost:5000),浏览器的同源策略可能导致请求被阻止。在后端服务中添加适当的CORS头信息,允许跨域请求。

    在Flask中添加CORS头信息的示例代码如下:

    安装 Flask-CORS 扩展:首先,需要安装 Flask-CORS 扩展。您可以使用 pip 安装:

    pip install flask-cors
    
    from flask import Flask
    from flask_cors import CORS
    
    app = Flask(__name__)
    CORS(app)
    
    # 定义路由和处理逻辑...
    
    if __name__ == '__main__':
        app.run()
    

    使用flask_cors库中的CORS对象,可以为Flask应用添加CORS支持,允许跨域请求。

    扩展:
    配置 CORS:您可以根据需要配置 CORS,例如指定允许的源(Origin)或请求头。

    # 允许所有来源访问
    CORS(app, resources={r"/*": {"origins": "*"}})
    
    # 允许特定来源访问
    CORS(app, resources={r"/*": {"origins": "http://example.com"}})
    
    # 允许多个来源访问
    CORS(app, resources={r"/*": {"origins": ["http://example.com", "http://example2.com"]}})
    
    1. 请求路径错误:确保前端应用使用正确的请求路径来调用后端服务。检查请求的URL和路由定义是否匹配。

    2. 请求方法不匹配:确保前端应用使用与后端服务路由定义相匹配的请求方法(GET、POST、PUT、DELETE等)。检查前端应用代码中的请求方法和后端服务中路由的定义是否一致。

    3. 服务未正确启动:确保后端服务已经正确启动,并且监听指定的端口。检查后端服务的日志输出,查看是否有错误或异常信息。

    通过检查上述问题,你可以逐步定位并解决前端无法调用后端服务的原因。

    四、接收数据的方式以及请求

    方式一:放文件路径上

    路径:/api/this_api?path=“****”
    代码里:

    path = request.args.get('path')
    

    请求方式:

    curl -X POST “http://ip:port/api/this_api?path=*****”
    

    方式二:form data

    路径:/api/this_api
    代码里:

    path = request.form.get('path')
    

    请求方式:

    curl -X POST -d “path=*****” http://ip:port/api/this_api
    

    五、如果后端返回的数据前端接收不到

    因为没有返回信息头校验权限

    return 内容, 200, {"Access-Control-Allow-Credentials": "true"}
    

    六、调用说明

  • 启动docker
    docker run的时候带的选项要注意一下加上-p ip(外部访问的地址):5000(主机端口):5000(容器端口) 比如:
  • docker run -p 192.168.0.1:5000:5000 XXXX
    

    注意以上docker命令不完整,完整的docker命令详细版请参考基于NVIDIA的dockerfile实操

  • 写服务时
  • if __name__ == "__main__":
        app.run(host='0.0.0.0', port=5000)
    
  • 调用时
  • 示例:

    curl -X POST "http://192.168.0.1:5000/api/this_api?path=*****"
    

    七、返回中文编码问题

    参考:https://blog.51cto.com/qzcsbj/5016619

    如此返回即可:

    res = {"ret": 0, "msg": "ok", "res":"我要返回中文"}
    return json.dumps(res, ensure_ascii=False)
    

    参考文章:https://blog.csdn.net/ThomasCai001/article/details/131193932

    参考文档: 如何理解 flask 中的 Blueprint 的 name 参数 – 简书 (jianshu.com)

    参考文档:Flask框架入门教程(非常详细)从零基础入门到精通,看完这一篇就够了-CSDN博客

    作者:五月天的尾巴

    物联沃分享整理
    物联沃-IOTWORD物联网 » 使用Flask编写Python后端接口,实现服务端提供接口并处理JSON数据和数组

    发表回复