second_服務器項目搭建_基於flask-JSONRPC提供的RPC_APICloud


 

2. 服務端項目搭建

進入服務器,安裝各種包

sudo apt-get update  # 更新相關源
sudo apt-get install git  # 按照git

# mysql的安裝
sudo apt-get install mysql-server
sudo apt-get install libmysqlclient-dev

 

進入數據庫, 剛安裝完成的數據庫,root是空密碼,所以要修改root的密碼

mysql -uroot -p

# 修改密碼
use mysql;
update user set authentication_string=password('新密碼') where user='root' and Host ='localhost';
update user set plugin="mysql_native_password"; 

# 刷新權限
flush privileges;

 

創建數據庫命令如下:

create database mogu charset=utf8mb4;

 

redis安裝

sudo apt-get install redis-server

注意,redis安裝完成以后,要觀察redis是否啟動了,如果沒有啟動,則參考之前redis筆記,啟動redis。

# 查看是否啟動redis-server,一般是沒啟動
# 原因是現在的雲服務器基本都默認給redis配置一個IPV6的綁定地址。而我們大部分人的服務器是沒使用IPV6的
ps -aux | grep redis

# 如果沒有啟動,則運行以下命令,再查看是否啟動成功,再不行,則查看下面 注意事項
redis-server /etc/redis/redis.conf

 

注意事項:給服務器開通redis的6379,你也可以把全部端口打開(騰訊雲可以)

 

安裝虛擬環境

默認情況下ubuntu18.04版本中已經內置了Python3.6.7了。但是沒有內置pip。所以先安裝pip。

sudo apt install python3-pip
pip3 install virtualenv
pip3 install virtualenvwrapper

安裝完成了以后,接下來需要配置系統環境變量

mkdir $HOME/.virtualenvs

執行命令,打開並編輯 ~/.bashrc

vim  ~/.bashrc

文件末尾添加以下幾行代碼(注意最后一句命令,和我們本地的有所不同),:wq 保存退出。

export WORKON_HOME=$HOME/.virtualenvs
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
source /usr/local/bin/virtualenvwrapper.sh

可以用一下操作查看到你的虛擬環境實際地址

 whereis virtualenvwrapper   # 查看地址
/home/ubuntu/.local/bin/virtualenvwrapper.sh

刷新配置文件

source ~/.bashrc

虛擬環境中安裝基本模塊

創建虛擬環境

mkvirtualenv mogu -p python3

安裝依賴模塊

pip install flask==1.0.3
pip install pymysql==0.9.3
pip install redis==3.2.1
pip install flask-sqlalchemy==2.4.0
pip install flask-mysqldb==0.2.0
pip install flask-session==0.3.1
pip install flask-script==2.0.6
pip install flask-migrate==2.5.2

我們把項目搭建在/home/mogu目錄下

cd /home
mkdir moguapp
cd moguapp
# 創建flask項目啟動文件manage.py
vim manage.py

manage.py文件代碼:

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
  return 'hello,moluo~'

if __name__ == '__main__':
  app.run(host="0.0.0.0")

在終端下使用python manage.py運行測試服務器

python manage.py

前面我們已經在雲服務器控制台的網絡安全組中添加5000端口,所以可以直接通過瀏覽器進行訪問。

到碼雲上面,創建一個git倉庫,把服務器代碼上傳到碼雲

git config --global user.name "mooluo"
git config --global user.email "649641514@qq.com"
git init
git add .
git commit -m "創建manage.py啟動文件"
git remote add origin https://gitee.com/mooluo/moguapp.git
git push -u origin master

 

3. 服務端項目初始化

apt install tree

目錄結構

moguapp/
├─ logs/                   # 日志文件存儲目錄
├─ apps/                   # 項目主要邏輯業務代碼保存目錄
│  ├─ __init__.py          # 項目初始化文件
│  ├─ modules/             # 保存項目中所有api模塊的存儲目錄
│  │  ├─ common/           # 公共api接口目錄
│  │  │  ├─ __init__.py    # 公共api接口的初始化文件
│  │  │  ├─ models.py      # 公共api接口的模型文件
│  │  │  └─ api.py         # 公共api接口代碼文件
│  │  └─ __init__.py
|  ├─ utils/               # 項目自定義封裝工具包目錄
|  ├─ libs/                # 項目第三方工具包目錄
|  ├─ settings/            # 項目配置存儲目錄
│  │  ├─ dev.py            # 開發階段的配置文件
│  │  ├─ prop.py           # 生產階段的配置文件
│  │  └─ __init__.py
│  └─ statics/             # 保存項目中所有的靜態資源文件[img/css/js]
└── manage.py              # 項目的終端管理腳本文件

Config項目配置

settings/__init__.py 編寫基本配置代碼

import redis
class Config(object):
    """項目配置信息"""
    # 設置密鑰,可以通過 base64.b64encode(os.urandom(48)) 來生成一個指定長度的隨機字符串
    SECRET_KEY = "T1vEjTCjkGon5vU8C6Xq3ujNSQgHQje"
    # 配置日志
    LOG_LEVEL = "DEBUG"

    # 調試模式
    DEBUG = True

    # 數據庫的配置信息
    SQLALCHEMY_DATABASE_URI = "mysql://root:123456@127.0.0.1:3306/mogu?charset=utf8"
    SQLALCHEMY_TRACK_MODIFICATIONS = True
    SQLALCHEMY_ECHO = True

    # redis配置
    REDIS_HOST = "127.0.0.1"
    REDIS_PORT = 6379

    # session 配置
    SESSION_TYPE = "redis"  # 指定 session 保存到 redis 中
    SESSION_USE_SIGNER = True  # session_id 進行加密簽名處理
    SESSION_REDIS = redis.StrictRedis( host=REDIS_HOST, port=REDIS_PORT,db=1 )
    PERMANENT_SESSION_LIFETIME = 24 * 60 * 60 # session 的有效期,單位是秒

settings/dev.py編寫開發環境的配置信息,代碼:

from . import Config
class DevelopementConfig(Config):
  """開發模式下的配置"""
  pass

settings/prop.py編寫生產環境的配置信息,代碼:

from . import Config
class ProductionConfig(Config):
    """生產模式下的配置"""
    DEBUG = False
    LOG_LEVEL = "INFO"
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    SQLALCHEMY_ECHO = False

配置項目日志

把日志設置封裝成一個函數init_log,保存到utils/log.py文件中

import logging
from logging.handlers import RotatingFileHandler

# 把日志相關的配置封裝成一個日志初始化函數
def init_log(Config):
    # 設置日志的記錄等級
    logging.basicConfig(level=Config.LOG_LEVEL)  # 調試debug級
    # 創建日志記錄器,指明日志保存的路徑、每個日志文件的最大大小、保存的日志文件個數上限
    file_log_handler = RotatingFileHandler("logs/log", maxBytes=1024 * 1024 * 300, backupCount=10)
    # 創建日志記錄的格式 日志等級 輸入日志信息的文件名 行數 日志信息
    formatter = logging.Formatter('%(levelname)s %(filename)s:%(lineno)d %(message)s')
    # 為剛創建的日志記錄器設置日志記錄格式
    file_log_handler.setFormatter(formatter)
    # 為全局的日志工具對象(flaskapp使用的)添加日志記錄器
    logging.getLogger().addHandler(file_log_handler)

項目初始化代碼抽取

apps/__init__.py文件中,創建flask應用並加載配置

from flask import Flask
from redis import StrictRedis
from flask_session import Session
from flask_sqlalchemy import SQLAlchemy

from apps.settings.dev import DevelopementConfig
from apps.settings.prop import ProductionConfig
from apps.utils.log import init_log

config = {
    "dev": DevelopementConfig,
    "prop": ProductionConfig,
}

# 預設全局變量
redis_store = None
db = SQLAlchemy()

def init_app(config_name):
    """項目的初始化功能"""
    app = Flask(__name__)

    # 設置配置類
    Config = config[config_name]

    # 加載配置
    app.config.from_object(Config)

        # redis的鏈接初始化
    global redis_store
    redis_store = StrictRedis(host=Config.REDIS_HOST, port=Config.REDIS_PORT,db=0)

    # 開啟session功能
    Session(app)
    
    # 配置數據庫鏈接
    db.init_app(app)

    # 啟動日志
    init_log(Config)

    return app

配置項目啟動文件

manage.py啟動文件中,加載app初始化工廠函數,並使用flask-script啟動項目

# coding=utf-8
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand

from apps import init_app,db

app = init_app("dev")

# 使用終端腳本工具啟動和管理flask
manager = Manager(app)

# 啟用數據遷移工具
Migrate(app, db)
# 添加數據遷移的命令到終端腳本工具中
manager.add_command('db', MigrateCommand)

@app.route('/')
def index():
  return 'hello,moluo~'

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

在虛擬環境重新使用manage.py啟動項目

sudo pip install flask_script
sudo pip install flask_migrate
sudo easy_install redis
python manage.py runserver --host=0.0.0.0 --port=5000

 

4. 基於Flask-JSONRPC提供RPC接⼝

JSON-RPC是一個無狀態的、輕量級的遠程過程調用(RPC)協議。

所謂的RPC,Remote Procedure Call的簡寫,中文譯作遠程過程調用或者遠程服務調用

直觀的理解就是,通過網絡來請求服務,獲取接口數據,而不用知曉底層網絡協議的細節。

RPC支持的格式很多,比如XML格式,JSON格式等等。最常用的肯定是json-rpc。

 

JSON-RPC協議中的客戶端一般是為了向遠程服務器請求執行某個方法/函數。客戶端向實現了JSON-RPC協議的服務端發送請求,多個輸入參數能夠通過數組或者對象傳遞到遠程方法,這個遠程方法也能返回多個輸出數據,具體是什么,當然要看具體的方法實現。

所有的傳輸都是單個對象,用JSON格式進行序列化。

請求要求包含三個特定屬性:

jsonrpc: 用來聲明JSON-RPC協議的版本,現在基本固定為“2.0”

method,方法,是等待調用的遠程方法名,字符串類型

params,參數,對象類型或者是數組,向遠程方法傳遞的多個參數值

id,任意類型值,用於和最后的響應進行匹配,也就是這里設定多少,后面響應里這個值也設定為相同的
響應的接收者必須能夠給出所有請求以正確的響應。這個值一般不能為Null,且為數字時不能有小數。

響應也有三個屬性:

result,結果,是方法的返回值,調用方法出現錯誤時,必須不包含該成員。

error,錯誤,當出現錯誤時,返回一個特定的錯誤編碼,如果沒有錯誤產生,必須不包含該成員。

id,就是請求帶的那個id值,必須與請求對象中的id成員的值相同。請求對象中的id時發生錯誤(如:轉換錯誤或無效的請求),它必須為Null

當然,有一些場景下,是不用返回值的,比如只對客戶端進行通知,由於不用對請求的id進行匹配,所以這個id就是不必要的,置空或者直接不要了。

在flask中要實現提供json-rpc接口,開發中一般使用Flask JSON-RPC模塊來實現。

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

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

安裝Flask-JSONRPC模塊

pip install Flask-JSONRPC==0.3.1

快速實現一個測試的RPC接口。

例如,我們直接在manage.py啟動文件中直接實現。

from apps import init_app,db
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from flask_jsonrpc import JSONRPC

app = init_app("dev")

# 使用終端腳本工具啟動和管理flask
manager = Manager(app)

# 啟用數據遷移工具
Migrate(app, db)
# 添加數據遷移的命令到終端腳本工具中
manager.add_command('db', MigrateCommand)

@app.route('/')
def index():
  return 'hello,moluo~'

# 初始化jsonrpc模塊
jsonrpc = JSONRPC(app, '/api')

# 實現rpc接口
@jsonrpc.method('Common.index')
def index():
    return u'Welcome to Flask JSON-RPC'


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

客戶端需要發起post請求,訪問地址為:http://服務器地址:端口/api

注意

默認情況下,/api接口只能通過post請求訪問。如果要使用jsonrpc提供的界面調試工具,則訪問地址為:

http://服務器地址端口/api/browse/

訪問數據格式應是:

{
    "jsonrpc": "2.0",
    "method": "Common.index",
    "params": {},
    "id": "1"
}

 

通過postman訪問效果:

對RPC接口代碼進行模塊化分離

把jsonrpc模塊的初始化代碼抽離到app對象初始化函數init__app中。

apps/__init__py,代碼:

from flask import Flask
from redis import StrictRedis
from flask_session import Session
from flask_sqlalchemy import SQLAlchemy
from flask_jsonrpc import JSONRPC

from apps.utils.log import init_log
from apps.settings.dev import DevelopementConfig
from apps.settings.prop import ProductionConfig

config = {
    "dev": DevelopementConfig,
    "prop": ProductionConfig,
}

# 預設全局變量
redis_store = None
db = SQLAlchemy()
# 創建jsonrpc實例對象
jsonrpc = JSONRPC(app=None, service_url='/api', enable_web_browsable_api=True)

def init_app(config_name):
    """項目的初始化功能"""
    app = Flask(__name__)

    # 設置配置類
    Config = config[config_name]

    # 加載配置
    app.config.from_object(Config)

    # redis的鏈接初始化
    global redis_store
    redis_store = StrictRedis(host=Config.REDIS_HOST, port=Config.REDIS_PORT,db=0)

    # 開啟session功能
    Session(app)
    
    # 配置數據庫鏈接
    db.init_app(app)

    # 啟動日志
    init_log(Config)

    # jsonrpc注冊到app應用對象中
    jsonrpc.init_app(app)

    return app

modules/common/api.py,代碼:

from apps import jsonrpc
# 實現rpc接口
@jsonrpc.method('Common.index')
def index():
    return u'Welcome to Flask JSON-RPC'

manage.py啟動文件中加載api接口

from apps import init_app,db
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand

app = init_app("dev")

# 使用終端腳本工具啟動和管理flask
manager = Manager(app)

# 啟用數據遷移工具
Migrate(app, db)
# 添加數據遷移的命令到終端腳本工具中
manager.add_command('db', MigrateCommand)

# api接口列表
from apps.modules.common import api

@app.route('/')
def index():
  return 'hello,moluo~'

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

重新啟動項目,使用postman進行還是原來的結果,則表示調整成功,后面的開發中,我們只需要不斷增加對應的接口即可。

使用jsonrpc接受客戶端請求的參數

服務器提供rpc接口方法:

from apps import jsonrpc

@jsonrpc.method("模塊名.方法名(username=String, password=String)")
def 方法名(username,password):
    return u"賬號:%s,密碼:%s" % (username,password)

客戶端發送請求:

{
    "jsonrpc": "2.0",
    "id": 188,
    "method": "Common.add",
    "params": {
        "username":"xiaohui",
        "age":33,
        "sex":false,
        "lve":["吃飯","睡覺",3,4,{"title":"aaaa"}],
        "son":{
            "username":"xiaohuihui",
            "age":12
        }
    }
}

實現jsonrpc接口的版本迭代

基於flask_jsonrpc.site.JSONRPCSite 來實現

apps/__init__代碼:

from flask import Flask
from redis import StrictRedis
from flask_session import Session
from flask_sqlalchemy import SQLAlchemy
from flask_jsonrpc import JSONRPC
from flask_jsonrpc.site import JSONRPCSite
from apps.settings.dev import DevelopementConfig
from apps.settings.prop import ProductionConfig
from apps.utils.log import init_log

config = {
  "dev": DevelopementConfig,
  "prop": ProductionConfig,
}

# 預設全局變量
redis_store = None
db = SQLAlchemy()
# jsonrpc實例化
jsonrpc = JSONRPC(service_url="/api/v1", site=JSONRPCSite(), enable_web_browsable_api=True)
jsonrpc_v2 = JSONRPC(service_url="/api/v2", site=JSONRPCSite(), enable_web_browsable_api=True)


def init_app(config_name):
  
  。。。。

  # 啟動日志
  init_log(Config)

  # 把jsonrpc注入到app實例對象中
  jsonrpc.init_app(app)
  jsonrpc2.init_app(app)

  return app

模塊目錄modules/common/api.py,代碼:

from apps import jsonrpc,jsonrpc2

@jsonrpc.method("Common.add(username=String,age=Number,sex=Boolean,lve=Array,son=Object)")
def add_v1(username,age,sex,lve,son):
  return "username=%s,age=%s,sex=%s,lve=%s,son=%s" % (username,age,sex,lve,son)

@jsonrpc2.method("Common.add(username=String,age=Number,sex=Boolean,lve=Array,son=Object)")
def add_v2(username,age,sex,lve,son):
  return u"賬號=%s,年齡=%s,性別=%s,愛好=%s,后代=%s" % (username,age,sex,lve,son)

5. APICloud的基本入門

.
|-- config.xml         # app核心配置文件
|-- css/               # 公共css存儲目錄
|   |-- api.css
|   `-- style.css
|-- feature            # 啟動畫面圖片
|-- html/              # 頁面/窗口的文件存儲目錄
|-- icon               # 手機應用圖標
|-- image/             # 靜態圖片存儲目錄
|-- index.html
|-- launch             # 啟動畫面圖片
|-- res                # 除了圖片以外的其他文件
|-- script/            # javascript文件存儲目錄
|   `-- api.js
`-- wgt                # app模塊目錄

歡迎頁面

歡迎頁面是用戶打開APP看到的第一個頁面,我們要實現歡迎頁面,首先要弄清楚APICloud開發過程中的幾個關於頁面的概念:

window       APP的窗口
Frame        窗口里面的框架頁面
FrameGroup   框架頁面的組合
api.openWin({
    name: 'page1',        # window名字
    url: './page1.html',  # 頁面地址,可以為本地文件路徑,支持相對路徑和絕對路徑
    pageParam: {          # 頁面參數,新頁面中可以通過 api.pageParam 獲取
        name: 'test'
    }
});

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM