flask-app02

Posted 贰号猿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了flask-app02相关的知识,希望对你有一定的参考价值。


移动端开发相关概念

APP类型

 

Native APP

Native APP又称原生APP,就是我们平时说的手机/桌面应用软件。

原生APP 是针对IOS、Android、Windows、鸿蒙等不同的手机操作系统要采用不同的语言和框架进行开发出来的,通常是由“服务器数据+APP应用客户端”两部份构成。

实现技术:

iOS: swift(雨燕)/ Object-C
Android: java / kotlin
HarmonyOS: JS, Java和C++

 

优缺点

优点:
体验好,用户无法上网也可访问APP应用中以前下载的数据
性能稳定,可调用手机的硬件设备(语音、摄像头、短信、GPS、重力感应等)和本地资源(通讯录,相册等)
操作速度快,能够实现出色的动效,转场动画完美

缺点:
开发周期长,开发人员工资起点高。
用户要使用原生APP,必须通过安装到手机里面才行,而且APP软件体积大,占用较多手机内存容量
更新缓慢,根据不同平台,提交–审核–上线流程较复杂。
要获取最新功能,需要升级应用,所以会容易出现有些用户不升级,导致多个不同功能版本出现,维护成本大
跨平台差,每种平台都需要独立的开发语言。Java(安卓),swift(iOS), HarmonyOS(java、C++、js)等等

 

Web APP

Web APP本质上是为移动浏览器设计的网站,可以在各种智能设备的浏览器上运行。

实现技术:

HTML5+Javascript+CSS3
react.js
vue.js

 

优缺点

优点:
一套代码到处运行,可以同时在 PC、Android、iPhone、鸿蒙系统上的浏览器上访问
开发者不需要发布到应用市场审核,用户不需要下载、安装和更新
开发周期短,维护成本低
用户不需用户手动更新,可以自动更新,直接使用最新版本

缺点:
转场表现略差,要求联网
用户体验没那么炫。图片和动画支持性不高
没法在应用市场中下载、无法通过应用下载获得盈利机会
对手机功能应用缺乏,有限制(蓝牙、网络、本地文件等)

 

Hybrid APP

Hybrid App就是混合APP,就是Native结合Web的混合开发,就是内部本质是Web网页,使用外壳打包软件给它套一层原生APP的外壳。

实现技术:

APICloud -> apicloud template ---> APICloud编辑器 ---> 混合APP
DCloud的uni-app ->Hbuilder编辑器 -> 混合APP
​
WeX5
phoneGap(cordova(浏览器内核)+android(引擎))
Ionic4
React Native (react.js+APP外壳程序)
....
 

 

优缺点

优点:
集众家之长,既可以调用丰富的手机设备API,也能拥有Web APP的跨平台能力
可以在应用商店发布,实现收费下载
内部是网页结构,可以自主更新,做到开发一次,所有平台生效
降低开发成本和技术成本,降低维护和开发周期
缺点:
本质上就是一个Web APP使用了原生APP的壳,所以体验比不上原生APP,但是比webAPP强
开发难度比Web APP高,有一定的学习成本,开发周期比Web APP长,但是比原生APP肯定要短。
混合APP发布有可能无法通过审核,需要多次调整,才能发布
依赖开发框架本身提供的手机设备API,少部分设备功能还是只能借助原生语言进行调用才可以
对团队技术栈要求相对高,既要懂web开发的,也要懂原生APP开发的

 

移动端适配方案

目前常用的布局适配方案就3种,分别是vw像素百分比+flex弹性布局rem+viewportvw最流行最容易。

当然,rem+viewport这种方案的实现方式也有很多,其中最著名的就是淘宝的flexible方案

 

 

开发准备

我们接下来开发的项目是嘤鸣APP,主要通过Flask+json-rpc+APICloud+vue.js完成的。

 

注册APICloud帐号

APICloud官网:https://www.apicloud.com

开发文档:https://docs.apicloud.com

 

下载APP开发编辑器

注册成功,登录进入开发控制台,找到页面右下角点击开发工具跳转到工具下载页面。

 

 

网站地址:https://www.apicloud.com/studio3

 

 

安装目录不能有中文!!!打开效果如下:

 

使用APICloud上注册的账户登录。

 

接下来开发APP的时候,肯定是要查看代码运行后的效果,所以我们需要安装安卓模拟器,当然也可以使用真机调试。

推荐: 市面上大部分的模拟器都差不多,使用人数最多,一般都是: 海马玩模拟器, 夜神模拟器, 雷电模拟器.

我们这里安装和使用雷电模拟器。

 

官网: https://www.ldmnq.com/

注意哦:

如果使用mac os 开发的同学,安装夜神模拟器.

夜神的官网: https://www.yeshen.com/

安装完成以后:

 

上面这个版面效果是平板的,所以我们调整下版面设置为移动端手机的。

 

 

最终效果:

 

 

下载APP开发调试工具

下载地址:https://docs.apicloud.com/Download/download

点击AppLoader下载APP加载器工具,如扫码无法下载,则手动下载压缩包,通过USB连接电脑拖动到手机中进行安装。

 

可以在真实手机中安装, 完成效果:

 

 

也可以在模拟器中安装, 完成效果:

 

移动端项目搭建

注意:在本地编辑器中创建项目,必须保证联网,并当前开发机子已经安装了SVN。

点击APICloud Studio3编辑器,选择左上角,创建项目。

 

创建原生应用,空白项目。

 

 

模拟器运行项目

 

 

手机真机运行项目

运行项目的前提是:必须通过USB或者测试的手机和当前开发的电脑处于同一个wifi网络中。

 

 

 

APICloud前端框架

APICloud内置了2个前端框架给我们操作APP页面和展示数据,这2个前端框架也都提供了ajax跨域请求数据功能。

这2个框架分别:APICloud前端框架和AVM前端框架。

APICloud前端框架

目录结构

APP/
  |- index.html   # 默认app配置的入口页面
  |- config.xml   # APP系统配置文件
  |- html/        # APP页面存储目录
  |- css/         # 样式目录
  |- script/      # js脚本目录
  |- image/       # 图片目录
 

 

调用框架

<script src="./script/api.js"></script>

 

APICloud 前端框架引入到HTML以后,会在当前页面提供一个全局对象$api$api在源码中提供的40多个操作HTML元素的方法,主要分6类用途:

数据操作:
trim() trimAll() isArray() jsonToStr() strToJson() get()
post()

事件操作:
one() addEvt() rmEvt()

元素查找:
dom() domAll() byId() first() last() eq() not() prev() next() contains() closest()

DOM操作:
remove() attr() removeAttr() hasCls() addCls() removeCls() toggleCls() val() prepend() append() before() after()
html() text() offset() css() cssVal()

本地存储:
setStorage() getStorage() rmStorage() clearStorage()

系统兼容:
fixIos7Bar() fixStatusBar()

APICloud中,所有的代码都必须在其提供的apiready入口函数中执行,才能调用APP系统设备的数据。

 

基本使用

<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,initial-scale=1.0,width=device-width" />
    <meta name="format-detection" content="telephone=no,email=no,date=no,address=no">
    <title>Hello APP</title>
    <link rel="stylesheet" type="text/css" href="./css/api.css" />
    <style type="text/css">
        html,
        body 
            height: 100%;
        

        .wrap 
            display: -webkit-box;
            -webkit-box-orient: vertical;
            -webkit-flex-flow: column;
        

        header 
            height: 44px;
            width: 100%;
            text-align: center;
            
            color: #fff;
            line-height: 44px;
            font-size: 20px;
        

        .flex-1 
            -webkit-box-flex: 1;
            -webkit-flex: 1;
        

        footer 
            height: 30px;
            width: 100%;
            
            color: white;
            line-height: 30px;
            text-align: center;
        
    </style>
</head>

<body class="wrap">
    <header>yingming</header>
    <button>点击按钮</button>
</body>
<script src="./script/api.js"></script>
<script>
    // 全部的js都必须写在一个APICloud提供apiready函数中,否则在调用手机系统的API功能时,会报错!!!
    apiready = ()=>
        // 获取元素
        let button = $api.dom(document, \'button\');
        // 绑定事件
        $api.addEvt(button, \'click\', ()=>
            api.alert("title":"哈哈哈哈");
        );
     
</script>
</html>

 

入口函数

理论上来说,要调用ApiCloud前端框架提供的方法, 不需要在apiready里面编写,在外面也可以操作到$api对象.
但是APICloud的原生外壳程序中还在系统中提供了另一个api对象,这个api对象就必须写在apiready中,而往往开发中,api对象发挥的作用和使用场景更多,因为api对象提供了页面跳转,打开窗口,访问设备API等功能,所以我们一般会选择把所有代码都写在APICloud提供的apiready入口函数中。

apiready = function()
    // api对象的操作代码....
    

 

 

配置文件

文档地址:https://docs.apicloud.com/Dev-Guide/app-config-manual

config.xml,代码:

<!-- id="A6181657864079" 表示当前项目的唯一标志服,对应着APICloud平台上面的代码地址,所以不能乱改! -->
<widget id="A6181657864079" version="0.0.1">
    <!-- APP显示在移动端下的软件名称和描述信息 -->
    <name>yingming35</name>

    <description>Example For APICloud.</description>
    <!-- APP的作者信息,一般好就是邮箱、官网地址,作者名 -->
    <author email="developer@apicloud.com" href="http://www.apicloud.com">Developer</author>
    <!-- APP的启动页 -->
    <content src="index.html"/>
    <!-- 跨域设置 -->
    <access origin="*"/>
     <!-- 配置页面是否弹动 -->
    <preference name="pageBounce" value="false"/>
     <!-- 配置App全局背景 -->
    <preference name="appBackground" value="rgba(0,0,0,0.0)"/>
     <!-- 配置Window默认背景 -->
    <preference name="windowBackground" value="rgba(0,0,0,0.0)"/>
    <!-- 配置Frame默认背景 -->
    <preference name="frameBackgroundColor" value="rgba(0,0,0,0.0)"/>
    <!-- 配置页面默认是否显示滚动条  h是横向滚动条 v是竖直滚动条 -->
    <preference name="hScrollBarEnabled" value="false"/>

    <preference name="vScrollBarEnabled" value="false"/>
     <!-- 配置启动页是否自动隐藏 -->
    <preference name="autoLaunch" value="true"/>
    <!-- 配置应用是否全屏运行 -->
    <preference name="fullScreen" value="false"/>
    <!-- 配置应用是否自动检测更新 -->
    <preference name="autoUpdate" value="true"/>
    <!-- 配置应用是否支持增量更新、云修复 -->
    <preference name="smartUpdate" value="false"/>
    <!-- 配置应用开启/关闭调试模式 -->
    <preference name="debug" value="true"/>
    <!-- 配置iOS状态栏和页面是否重合(沉浸式效果) -->
    <preference name="statusBarAppearance" value="true"/>
    <!-- 读取手机状态和身份 -->
    <permission name="readPhoneState"/>
    <!-- 使用拍照和视频 -->
    <permission name="camera"/>
    <!-- 使用录音 -->
    <permission name="record"/>
    <!-- 访问地理位置信息 -->
    <permission name="location"/>
    <!-- 访问文件系统 -->
    <permission name="fileSystem"/>
    <!-- 完全的访问网络权限 -->
    <permission name="internet"/>
    <!-- 开机启动 -->
    <permission name="bootCompleted"/>
    <!-- 控制振动/闪光灯/屏幕休眠等硬件设备 -->
    <permission name="hardware"/>

</widget>

 

 

api与$api对象

注意:在APICloud中存在2个全局对象,分别是$api和api对象。这两个对象是不同的。

$api必须是在script标签通过src引入api.js文件以后才出现的对象,api是APP内置的全局对象,不需要引入内容就有的。

其中api对象主要是由APP系统提供给我们开发者操作和读取设备信息的。

$api是APICloud模仿了jquery的$对象提供给开发者用于操作app页面的对象。

api对象的操作代码必须写在apiready入口函数中,否则报错!

$api的部分操作代码,则不会报错,但是强烈建议不管是$api还是api都写进入口函数中。

代码:

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0"/>
    <meta name="format-detection" content="telephone=no,email=no,date=no,address=no">
    <title>嘤鸣APP</title>

</head>
<body>
    <div id="wrap">
        <div id="header">
            <h1>python 移动端开发~~~</h1>
        </div>
        <div id="main" class="flex-con">

        </div>
        <div id="footer">
            <h5>Copyright &copy;<span id="year"></span> </h5>
        </div>
        <div id="info">

        </div>
    </div>
</body>
<script type="text/javascript" src="./js/api.js"></script>
<script type="text/javascript">

    apiready = function()
        var header = document.querySelector(\'#header\');
        $api.fixStatusBar(header);

        var el = $api.byId("header");
        var h1 = $api.first(el);
        var content = $api.html(h1,"2020-08-27");


        var ver = api.version;
            var sType = api.systemType;
            var sVer = api.systemVersion;
            var id = api.deviceId;
            var model = api.deviceModel;
            var name = api.deviceName;
            var cType = api.connectionType;
            var winName = api.winName;
            var winWidth = api.winWidth;
            var winHeight = api.winHeight;
            var frameName = api.frameName || \'\';
            var frameWidth = api.frameWidth || \'\';
            var frameHeight = api.frameHeight || \'\';

            var str = \'<ul>\';
            str += \'<li>引擎版本信息: \' + ver + \'</li>\';
            str += \'<li>系统类型: \' + sType + \'</li>\';
            str += \'<li>系统版本: \' + sVer + \'</li>\';
            str += \'<li>设备标识: \' + id + \'</li>\';
            str += \'<li>设备型号: \' + model + \'</li>\';
            str += \'<li>设备名称: \' + name + \'</li>\';
            str += \'<li>网络状态: \' + cType + \'</li>\';
            str += \'<li>主窗口名字: \' + winName + \'</li>\';
            str += \'<li>主窗口宽度: \' + winWidth + \'</li>\';
            str += \'<li>主窗口高度: \' + winHeight + \'</li>\';
            str += \'<li>子窗口名字: \' + frameName + \'</li>\';
            str += \'<li>子窗口宽度: \' + frameWidth + \'</li>\';
            str += \'<li>子窗口高度: \' + frameHeight + \'</li>\';
            str += \'</ul>\';

        $api.html($api.byId("info"), str);

    ;
</script>
</html>
 

 

获取服务端API接口

 

因为,我们当前开发的APICloud实际将来是运行在了Android系统下,是属于另一个设备下的操作系统。

同时,我们当前开发的服务端flask框架提供的接口代码是在虚拟机下的Ubuntu下面,因此,安卓和ubuntu实际上相互之间是不在一个网络下面的。但是开发过程中,我们必须要让客户端通过http请求,访问到服务端的API接口数据。因此,我们需要让windows实现一个代理访问。让客户端直接请求到windows下,然后windows把客户端请求转发给Ubuntu。

 

VMWare实际上是直接设置请求代理的。所以配置如下:

点击打开VMWare的菜单栏的“编辑”,点选"虚拟网络编辑器",打开编辑器的窗口。

 

先选择上方的NAT模式网络设置,然后点选 NAT设置(s)....

 

点击添加,表示添加一个端口转发设置。

 

 

 

上面的设置完成以后,就可以在windows下的浏览器中,直接访问本地127.0.0.1:5000也可以访问到Ubuntu下面了。

 

接下来,后面就可以让安卓模拟器中的APP直接访问到windows下的5000端口,然后VMWare就会进行端口转发了。那么我们就需要让安卓模拟器知道windows的IP地址。因为安卓模拟器和windows处于同一个网络下的,所以我们可以之前安装APPLoader工具的绿色按钮,查看windows的IP地址。

 

所以,在客户端的代码中,采用上面的IP地址+5000端口,结合API接口的访问地址,就可以在app中获取服务端的数据了。

api.ajax

获取数据可以使用APICloud前端框架提供的$api.post()或者$api.get(),当然,也可以使用APP原生提供的提供的api.ajax

基本语法:

api.ajax(
      url: \'API接口地址\',                 // 必须加上协议
      method: \'请求方法\',                 // post、get、put、delete、patch
      dataType: "json",                  // 服务端数据响应格式
      cache: true,                       // 缓存数据,若缓存,下次没网络时请求则会使用缓存,
                                         // 仅在get请求有效
      timeout: 30,                       // 超时时间,单位:秒
      headers:,                        // 请求头,里面的key使用首字母大写的形式,
                                         // 如 Content-Type
      report:false,                      // 是否实时返回上传文件的进度,只有上传时使用
      data:                             // 提交请求体的数据
          values:                       // 以表单格式提交数据
              name: \'haha\'
          ,
          body: "",                      // 以字符串格式提交数据,body和values是冲突的,只能使用其中一个
          files:                        // ajax上传文件
              file: \'fs://a.gif\'         // 文件字段名
          
      
  ,function(ret, err)                  // 回调函数,参数1是响应内容,参数2是错误信息
      if (ret) 
          alert( JSON.stringify( ret ) );
       else 
          alert( JSON.stringify( err ) );
      
  );

 

接下来的开发中,我们需要实现客户端,所以如果基于上面的$api开发的话,非常的影响效率,所以我们可以采用Vue.js来完成app的客户端开发.当然最终代码还是运行在APICloud里面.

 

vue+axios

vue.js:https://vuejs.org/js/vue.js

axios.js:https://www.npmjs.com/package/axios

把下载回来的vue.js和axios.js保存到项目的scripts目录下,然后在页面中引入。

<script src="../script/vue.js"></script>
<script src="../script/axios.js"></script>
<script src="../script/main.js"></script>

 

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../script/vue.js"></script> <!-- Alt+Shift+↑/↓ -->
    <script src="../script/axios.js"></script>
</head>
<body>
    <div id="app">
        <h1 @click="getData">text</h1>
    </div>
    <script>
        apiready = function()
            var vm = new Vue(
                el: "#app",
                data()
                    return 
                        text: "点击按钮"
                    
                ,
                methods: 
                    getData()
                        // 弹窗,提示
                        // api.alert(
                        //     "title": "标题",
                        //     "msg": "hello!!!"
                        // )

                        // 在APICloud中打印数据,不能直接打印,需要转换成json才能打印
                        // data = "name":"xiaoming"
                        // console.log(data);  // [object Object] at index.html:26
                        // console.log(JSON.stringify(data)); // "name":"xiaoming" at index.html:28
                        
                        // api对象提供的网络请求
                        // api.ajax(
                        //     url:\'http://192.168.19.251:5000/home/test\'
                        // , (ret, err)=>
                        //     console.log(JSON.stringify(ret));
                        // );

                        axios.get("http://192.168.19.251:5000/home/test").then(response=>
                            console.log(JSON.stringify(response.data));
                        )
                    
                
            )
        
    </script>
</body>
</html>

 

服务端代码,application/apps/home/views.py,代码:

def test():
    return "title":"测试标题"

 

路由代码:

from typing import List
from application import path
from . import views

urlpatterns: List = [
    path("/test", views.test, methods=["GET"]),
    path("/test", views.test, methods=["POST"]),
]

 

上面的代码是服务端提供了函数视图,当然,我们也可以提供基于restful的类视图接口。

服务端代码,application/apps/home/views.py,代码:

def test():
    return "title":"测试标题"

from flask.views import MethodView

class Home(MethodView):
    def get(self):
        return "title":"类视图的get代码"

    def post(self):
        return "title": "类视图的post代码"

 

路由代码:

from typing import List
from application import path
from . import views

urlpatterns: List = [
    path("/test", views.test, methods=["GET"]),
    path("/test", views.test, methods=["POST"]),
    path("/home", views.Home.as_view("home")),
]

 

客户端中的html/index.html,代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../script/vue.js"></script> <!-- Alt+Shift+↑/↓ -->
    <script src="../script/axios.js"></script>
</head>
<body>
    <div id="app">
        <h1 @click="getData">text</h1>
    </div>
    <script>
        apiready = function()
            var vm = new Vue(
                el: "#app",
                data()
                    return 
                        text: "点击按钮"
                    
                ,
                methods: 
                    getData()
                        // 弹窗,提示
                        // api.alert(
                        //     "title": "标题",
                        //     "msg": "hello!!!"
                        // )

                        // 在APICloud中打印数据,不能直接打印,需要转换成json才能打印
                        // data = "name":"xiaoming"
                        // console.log(data);  // [object Object] at index.html:26
                        // console.log(JSON.stringify(data)); // "name":"xiaoming" at index.html:28
                        
                        // api对象提供的网络请求
                        // api.ajax(
                        //     url:\'http://192.168.19.251:5000/home/test\'
                        // , (ret, err)=>
                        //     console.log(JSON.stringify(ret));
                        // );

                        // 发送get请求
                        // axios.get("http://192.168.19.251:5000/home/home").then(response=>
                        //     console.log(JSON.stringify(response.data));
                        // )
                        
                        // 发送post请求
                        axios.post("http://192.168.19.251:5000/home/home").then(response=>
                            console.log(JSON.stringify(response.data));
                        )
                    
                
            )
        
    </script>
</body>
</html>
 

 

JSON-RPC

所谓的RPC,Remote Procedure Call的简写,中文译作远程过程调用或者远程服务调用

直观的理解就是,通过网络请求远程服务器获取指定接口的数据,而不用知晓底层网络协议的细节。

RPC支持的数据格式很多,比如XML格式,JSON格式、ProtoBuf等等。最常用的肯定是json和ProtoBuf。我们接下来项目使用到的数据格式json格式。因为是属于前后端之间的数据交互。而如果是属于服务端之间的不同平台或服务端之间的不同语言之间的交互往往有很多人采用了ProtoBuf,因为ProtoBuf在执行和执行的过程中,都是非常高效的,因为ProtoBuf是属于二进制安全的。

JSON-RPC是一个无状态的、轻量级的远程过程调用(RPC)协议。

协议文档:https://www.jsonrpc.org/specification

译文文档:http://wiki.geekdream.com/Specification/json-rpc_2.0.html

JSON-RPC协议中的客户端一般是为了向远程服务器请求执行某个方法/函数。客户端向实现了JSON-RPC协议的服务端发送请求,多个输入参数能够通过数组或者对象传递到远程方法,这个远程方法也能返回多个输出数据,具体是什么,当然要看具体的方法实现。因为RPC可以通俗理解为:

客户端请求服务端完成某一个服务行为,所以JSON-RPC规范要求: 客户端发送的所有请求都是POST请求!!!

所有的传输数据都是单个对象,用JSON格式进行序列化。

请求要求包含三个特定属性:

jsonrpc: 用来声明JSON-RPC协议的版本,现在基本固定为“2.0”

method,方法,是等待调用的远程方法名,字符串类型

params,参数,对象类型或者是数组,向远程方法传递的多个参数值

id,任意类型值,用于和最后的响应进行匹配,也就是这里设定多少,后面响应里这个值也设定为相同的
响应的接收者必须能够给出所有请求以正确的响应。这个值一般不能为Null,且为数字时不能有小数。


   "jsonrpc": "2.0",
   "method": "模块名.方法名",
   "params": 
      "": "",
   ,
   "id": "UUID格式...."

 

响应也有三个属性:

jsonrpc, 用来声明JSON-RPC协议的版本,现在基本固定为“2.0”

result,结果,是方法的返回值,调用方法出现错误时,必须不包含该成员。

error,错误,当出现错误时,返回一个特定的错误编码,如果没有错误产生,必须不包含该成员。

id,就是请求带的那个id值,必须与请求对象中的id成员的值相同。请求对象中的id时发生错误(如:转换错误或无效的请求),它必须为Null

# 操作成功

    "jsonrpc": "2.0",
    "reslt": 
       data: 
       
       
    
    "id": "UUID格式(来自请求中的ID,原样返回)...."


# 操作失败

    "jsonrpc": "2.0",
    "error": 
       detail: 
       
       
    
    "id": "UUID格式(来自请求中的ID,原样返回)...."

 

当然,有一些场景下,是不用返回值的,比如只对客户端进行通知,由于不用对请求的id进行匹配,所以这个id就是不必要的,置空或者直接不要了。

 

在flask中要实现提供json-rpc接口,开发中一般使用Flask JSON-RPC模块来实现。

git地址:https://github.com/cenobites/flask-jsonrpc

 

安装Flask-JSONRPC模块

pip install Flask-JSONRPC

 

直接在application/__init__.py项目初始化文件中进行初始化jsonrpc,代码。

# 先写 import.. 后写 from .. import ...
# 先解析器内置,后框架官方,然后第三方模块,接着是自己封装的本地模块。

from pathlib import Path

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_redis import FlaskRedis
from flask_pymongo import PyMongo
from flask_jsonrpc import JSONRPC

from application.utils.config import init_config
from application.utils.logger import Log
from application.utils.commands import Command
from application.utils.blueprint import register_blueprint, path, include

"""加载组件[单例模式]"""
# SQLAlchemy实例化
db: SQLAlchemy = SQLAlchemy()

# redis实例化
redis_cache: FlaskRedis = FlaskRedis(config_prefix="REDIS")
redis_check: FlaskRedis = FlaskRedis(config_prefix="CHECK")

# mongoDB实例化
mongo: PyMongo = PyMongo()

# 日志实例化
logger:Log = Log()

# 终端命令管理类实例化
command: Command = Command()

# jsonrpc实例化
jsonrpc = JSONRPC()


def init_app(config_path: str) -> Flask:
    """用于创建app实例对象并完成初始化过程的工厂函数"""

    app: Flask = Flask(__name__)

    # 项目根目录
    app.BASE_DIR = Path(__file__).resolve().parent.parent

    # 初始化项目配置
    init_config(app=app, config_path=config_path)

    # SQLAlchemy加载配置
    db.init_app(app)

    # redis加载配置
    redis_cache.init_app(app)
    redis_check.init_app(app)

    # pymongo加载配置
    mongo.init_app(app)

    # 日志加载配置
    logger.init_app(app)

    # 终端命令管理类加载配置
    command.init_app(app)


    # jsonrpc注册到项目中
    # 开启rpc接口的web调试界面:/api/browse
    jsonrpc.browse_url = app.config.get("API_BROWSE_URL", "/api/browse")
    jsonrpc.enable_web_browsable_api = app.config.get("DEBUG", False)
    jsonrpc.init_app(app)

    # 注册蓝图
    register_blueprint(app)

    # db创建数据表
    with app.app_context():
        db.create_all()

    return app

 

application/settigns/__init__.py,代码:

"""JSONRPC"""
# api接口web调试界面的url地址
API_BROWSE_URL = "/api/browse"

 

提交版本

git add .
git commit -m "fix: add flask json rpc"
git push

 

快速实现一个测试的RPC接口。

application/apps/home/views.py,编写接口代码:

from flask import jsonify, request
def index():
    print(request.json)
    return "home.views.index"


def demo():
    data = "name":"xiaoming","age":16
    return jsonify(data)


from application import jsonrpc
# PEP484规范: 给所有的变量、函数/方法的返回值、参数,必须指定他们的类型
from typing import Union, Any, List, Dict
from numbers import Real


@jsonrpc.method("Home.menu")
def menu(data0: Any, data1: int, data2: float, data3: str, data4: Union[int, bool], data5: bool, data6: List[Any], data7: List[int], data8: Dict[str, Real]) -> List[Any]:
    ret = [
        data0,  # 可以填写任意类型数据
        data1,  # 只能填写整型
        data2,  # 只能填写浮点型
        data3,  # 只能填写字符串
        data4,  # Union表示联合类型, Union[int, bool]表示只能填写 整型和布尔型
        data5,  # 只能填写布尔型
        data6,  # List[Any],只能填写列表数据,列表中的成员可以是任意类型的数据
        data7,  # List[int],只能填写列表数据,列表中的成员只能是整型,除此之外,还有 List[str]、List[Dict[str, Any]]
        data8,  # [str, Real],只能填写字典数据,字典中的键必须是字符串,值必须是数值类型
    ]
    print(f"ret=ret")
    return ret

 

客户端需要发起post请求,访问地址为:http://127.0.0.1:5000/api/browse/#/

可以通过postman发送请求接口,访问数据格式应是:

截获Flask restplus名称空间类的验证错误

当前,名称空间解析器将验证请求参数并抛出错误,例如

{
    "errors": {
        "file": "Missing required parameter in an uploaded file"
    },
    "message": "Input payload validation failed"
}

从flask-app,我想拦截或处理这些异常,并发送自定义响应以获得一致性,例如{“错误”:{“ file”:“上载文件中缺少必需的参数”},“ message”:“输入有效负载验证失败”,“ id”:“某些客户ID”}

是否有可能从应用程序级别处理此异常,而不是对每个api都进行处理>

当前,命名空间解析器将验证请求参数,并引发类似{“ errors:{” file“:”上载的文件中缺少必需参数“},” message“:”输入...]的错误]

答案

根据此问题https://github.com/noirbizarre/flask-restplus/issues/530,有一种解决方法来获得个性化消息。

也就是说,可以通过BadRequest错误处理程序的定义来实现这一点,并修改data属性:

以上是关于flask-app02的主要内容,如果未能解决你的问题,请参考以下文章

顶点ai中的自定义容器部署

截获Flask restplus名称空间类的验证错误

如何克服对在正式教程中docker push所拒绝的资源的访问

Flask项目脚手架 -- Flask-Application正式发布

Flask项目脚手架 -- Flask-Application正式发布

Flask项目脚手架 -- Flask-Application正式发布