兩小時快速構建微信小程式

寒食君發表於2018-05-01

小程式在2017年1月上線之初,被社會極力吹捧,刻意去將其製造為一個“風口”,透支其價值。但是在之後一個月裡,石破天驚迅速歸為沉寂。媒體又開始過度消費小程式,大談其雞肋之處。

個人認為小程式的一個分水嶺是在12月28日。微信升級到6.6.1版本,將小程式入口移植主介面,下拉主介面即可選擇進入,並且支援新類目“小遊戲”。小程式逐漸升溫,在整個微信生態中扮演越來越重要的角色。時至今日,小程式的風潮如日中天,優秀的小程式很容易得到融資。這究竟是是另一輪泡沫,還是小程式本身真正已經進入了成熟期?我個人更相信後者。

我個人做過兩款小程式,對小程式有一定認識,但理解還是比較淺的。今天就僅從如何快速搭建一個小程式談起,揭開小程式的一絲神祕面紗。

概述

  • 小程式是前後端分離的。
  • 前端使用的是微信自定義的一套規範wxml+wxss+json+js,我認為本質還是html+css+js
  • 後臺可以選用任何你熟悉的語言:Java,Python,PHP,Ruby等等,在這篇文章裡我選用PythonFlask框架+Gunicorn+Nginx來快速搭建。
  • 資料庫我選擇MySQL,nosql資料庫我選擇Redis。當然,你的小程式可以很輕量級,甚至不需要使用到資料庫。小程式一大思想“用完即走”。
  • 後臺需要跑在一臺自己的伺服器上,同時你也需要一個已備案的https域名來進行對映。

附註

現在市面上也有一些第三方快速生成小程式的工具,和以前那些快速生成網站的是同一門生意。我個人並不推薦去使用那些,因為那些小程式幾乎千篇一律,無法結合你自己的創意,無法定製你需要提供的服務,而且必定存在一些收費。

當然,這些平臺既然存在,那麼必定是市場需求,假如確實適合你,能為你帶來一些效益,不妨一試。

今天,我們是以學習者的角度去構建小程式。

準備工作

  1. 一臺雲伺服器,可以上各大雲提供商平臺租用,我使用的是學生低配,¥10/月。
  2. 我在伺服器上使用的作業系統為ubuntu
  3. 購買一個域名,並通過備案。域名價格在1-10000000不等,我使用的是某com域名,¥50/年。
  4. 在微信公眾平臺註冊一個賬號並下載小程式開發工具。詳細說明
  5. httphttps。現在很多SSL證照可以免費申請,下面會詳細說下如何配置。

目標

我們的目標是實現一個簡單的小程式,能夠實現前後端對接。

從http到https

  1. 首先擁有一個已備案域名,並已經解析到你的伺服器上了。
  2. 如果你在阿里/騰訊雲租用了伺服器,可以申請免費的SSL證照。找到相應入口並申請就可以了。稽核一般很快,我的在一小時以內。
  3. 稽核通過後下載頒發的證照,先儲存在本地。之後通過ftp傳到伺服器的相應路徑。
  4. 在伺服器上安裝Nginx
  5. 首先測試你的Nginx服務是否能正常執行,配置完開啟自己的域名能顯示nginx的歡迎頁時即為成功配置。
  6. 然後將你的證照通過ftp上傳到伺服器的任意路徑下(建議和Nginx在同一路徑下)
  7. 開啟Nginx的配置檔案,如圖配置(證照路徑填寫自己的)
  8. 重啟服務,瀏覽器通過https訪問,能正常顯示頁面即為配置成功。
    image

前端

現在,開啟你的小程式開發工具,並使用你的APPID新建一個專案。(我這裡沒有多餘的APPID,所以先使用測試環境)

兩小時快速構建微信小程式

可以先勾選“建立普通快速啟動模板”來生成一個官方測試demo,如下圖:

兩小時快速構建微信小程式

讓我們來觀察一下目錄結構。app.js,app.json,app.wxss分別對應全域性的方法,全域性配置引數和全域性樣式。而在具體包下的index.js,index.wxml,index.wxss則對應相應的元素。

現在讓我們來寫一點簡單的頁面的程式碼。

<!-- index.wxml -->
<view class="main-card">
 <view class="main-card-item" id="toast" wx:if="{{news_flag}}">
    <view class="card-item-hd" >
      <image class="card-item-icon" src="/images/index/toast.png"></image>
      <text class="card-item-name">大事兒</text>
    </view>
    <view class='toast'>
     Hello,歡迎觀看此教程,希望對你有幫助。
    </view>
  </view>
</view>
複製程式碼
/* index.wxss */

page {
  background-color: #f8f8f8;
}

.main-card {
  padding-bottom: 100rpx;
}
.main-card-item{
  display: flex;
  flex-direction: column;
  background: #fff;
  border-top: 1rpx solid #F6F6EF;
  border-bottom: 1rpx solid #F6F6EF;
  margin-bottom: 20rpx;
  background-repeat: no-repeat;
  background-size: 100% auto;
  background-position: bottom center;
  overflow: hidden;
  margin-left: 12rpx;
  margin-right: 12rpx;
   border-radius: 15rpx;
}

.card-item-hd{
  display: flex;
  align-items: center;
  height: 75rpx;
  border-bottom: 1rpx solid #e5e5e5;
  margin-left: 30rpx;
}
.card-item-icon{
  width: 40rpx;
  height: 40rpx;
  margin-right: 10rpx;
}
.card-item-name{
  letter-spacing: 1px;
  font-size: 25rpx;
}
.toast{
  
  letter-spacing:3rpx;
  line-height: 50rpx;
  font-size: 28rpx;
  margin-left: 20rpx;
  margin-top: 20rpx;
  margin-bottom: 40rpx; 
  
}
複製程式碼

此時,一個簡單的頁面已經生成了,讓我們來看看效果。

兩小時快速構建微信小程式

很簡單,但是可以看出來「大事兒」裡的內容是寫死的,此時我們需要後端來提供資料。

###伺服器環境

在編寫後端之前,我們先把伺服器的環境部署一下。

安裝:

  1. 安裝了Python環境 apt-get install python-dev
  2. 安裝Flask pip install flask
  3. 安裝UWSGI pip install uwsgi
  4. 安裝了Nginx apt-get install nginx
  5. 安裝了Gunicorn pip install gunicorn

準備

首先在你的/var/www/目錄下建立一個測試目錄,比如/var/www# mkdir test

然後使用chmod更改此目錄的許可權chmod 777 /var/www/test

這裡講一下chmod規則,因為這裡是測試用例,所以為了方便,直接使用777。

Nginx

Ubuntu下的Nginx的目錄結構大致如下:

  1. 所有的配置檔案都在/etc/nginx下,每個虛擬主機已經安排在了/etc/nginx/sites-available目錄下
  2. 啟動程式檔案在/usr/sbin/nginx
  3. 日誌檔案放在了/var/log/nginx中,分別是access.logerror.log
  4. /etc/init.d/下建立了啟動指令碼nginx
  5. 預設的虛擬主機的目錄設定在了/usr/share/nginx/www

啟動服務:/etc/init.d/nginx start,重啟服務:/etc/init.d/nginx restart

現在,我們需要進入到Nginx的配置中,改動配置檔案。vim /etc/nginx/site-avalidable/default

兩小時快速構建微信小程式

兩小時快速構建微信小程式

更改配置檔案後重啟服務/etc/init.d/nginx restart,或者service nginx restart

Gunicorn

Gunicorn 綠色獨角獸 是一個Python WSGI UNIX的HTTP伺服器。這是一個pre-fork worker的模型,從Ruby的獨角獸(Unicorn )專案移植。該Gunicorn伺服器大致與各種Web框架相容,只需非常簡單的執行,輕量級的資源消耗,以及相當迅速。

此時需要在“準備”步驟中建立的測試目錄下放入我們的測試執行專案,我選擇的FTP工具是:xftp。我傳入了一個簡單的用來測試的Python檔案wsgi.py,使用命令/var/www/myflask# vim wsgi.py預覽。

wsgi.py

此時在測試目錄下鍵入命令gunicorn -w 4 -b 127.0.0.1:8000 wsgi:app執行。

開始執行

此時,訪問伺服器,可以看到“Hello World”已經可以正常顯示了。

hello world

關於Flask

後端我們採用PythonFlask框架+Gunicorn+Nginx來快速搭建。首先需要一些Python的基礎知識,相信大家在菜鳥學Python學了這麼久,這完全不是問題。現在,讓我們瞭解一下Flask如何使用。

一位使用多種語言開發複雜程式並且擁有十多年經驗的軟體工程師,曾經用 PHP, Ruby, Smalltalk 甚至 C++ 寫過 web 應用,他認為,在所有這些中,Python/Flask 組合是最為自由的一種。

在使用了Flask之後,我也不得不承認,它確實很便捷快速。當然也會有一定的缺點,這是後話。

迴歸正題。

獲得物件

from flask import Flask

app = Flask(__name__)
@app.route('/')
def hello_world():
    return 'Hello World'

if __name__ == '__main__':
    app.run() 
複製程式碼

這是一個最簡單的Demo。

執行流程為:從flask模組獲取物件app,通過路由,執行方法,返回內容。

此時在瀏覽器訪問(預設埠5000):127.0.0.1:5000/ ,可以看到國際慣例Helloworld的介面。

hello world

路由

  • 唯一URL:
@app.route('/hello')
@app.route('/hello/')
#這兩種需要區分
#
@app.route('/hello/')
#在使用這種尾部帶斜線的url時,假如使用者沒有輸入尾部/,也將訪問到正確的頁面
#
@app.route('/hello')
#在使用這種尾部不帶斜線的url時,假如使用者在尾部輸入了/,將返回404
複製程式碼

這個規則似乎有點拗口,但其實也不能理解。優點是:

  1. 使得使用者在遺忘尾斜線時,允許關聯的 URL 接任工作,與 Apache 和其它的伺服器的行為並無二異
  2. 保證了 URL 的唯一,有助於避免搜尋引擎索引同一個頁面兩次。

如果實在記不清,最好的方法是破罐子破摔:統一不帶尾部“/”

  • 構造URL中的動態部分
@app.route('/var/<name>')
def var(name):
    return 'hello'+' '+name
複製程式碼

這點就不贅述了,可以看一下演示效果:

hello ji

模板渲染

大部分時候,在使用者訪問了一個URL的時候,我們都需要給他/她返回一個介面,我們當然不會用Python本身去渲染HTML,為此,Flask 配備了Jinja2 模板引擎。

看完以下程式碼示例,相信你就能理解。

首先,我們建立“templates”資料夾用於儲存模板。

Flask 會在 templates 資料夾裡尋找模板。所以,如果你的應用是個模組,這個資料夾應該與模組同級;如果它是一個包,那麼這個資料夾作為包的子目錄:

#情況 1: 模組:
/application.py
/templates
    /hello.html

#情況 2: 包:
/application
    /__init__.py
    /templates
        /hello.html
複製程式碼
  1. 不含引數示例 在程式執行:
@app.route('/redi/')
def redi():
    return render_template('hello.html')
複製程式碼

hello.html:
hello

  1. 再看另一個例子,加入動態引數:
@app.route('/redi2/<name>')
def redi2(name):
    return render_template('hello2.html',name=name)
複製程式碼

hello2.html

hello ji

GET和POST

請求方式不止這個兩種,但是最常用的是這兩種,如果對這兩種不熟悉,可以先去查一下HTTP方法的資料,這裡只演示在flask中的用法。

@app.route('/met',methods=['GET','POST'])
def met():
    if request.method=='GET':
        return '這是get方法'
    if request.method=='POST':
        return '這是post方法'
複製程式碼

開啟Postman這款軟體(Web神器),模擬傳送HTTP請求。

get

post

請求物件

下面我來模擬一個簡單的登入操作。

首先是控制器:

@app.route('/login',methods=['POST','GET'])
def login():
    error=None
    if request.method=='POST':
        print (request.form['username']+' '+request.form['password'])
        if func.login_func.valid_login(request.form['username'],
                    request.form['password']):
            return func.login_func.login_success(request.form['username'])
        else:
            error='Invalid username/password'
            return render_template('login_error.html',error=error)
複製程式碼

可以看到執行流程:

  1. 獲得請求
  2. 判斷請求型別
  3. 獲得登陸資料
  4. valid_login()方法驗證登陸 4.1 若登陸成功,執行login_success()方法 4.2 若登入失敗,新增失敗資訊,返回失敗模板

下面是上述用到的兩個方法:

def valid_login(username,password):
    if username=='admin' and password=='admin':
        return True
複製程式碼
def login_success(username):
    return render_template('login_success.html',username=username)
複製程式碼

下面使用Postman來模擬請求,看看能不能返回設想的結果。

success

failure

這是一些簡單的Flask操作,好了,我們現在對web有了一定的瞭解了。現在開始編寫我們的程式碼。

###後端 萬事俱備,只欠東風。 首先我們來寫兩個路由,一個用於更新通知,一個用於獲取通知。

@app.route("/updateToast",methods=['POST'])
@allow_cross_domain
def update_toast():
    data=db_util.update_toast(request.form['toastUpdateInfo'])
    return jsonify(data)

@app.route("/getToast",methods=['GET'])
@allow_cross_domain
def get_toast():
    data = db_util.get_toast_info()
    return jsonify(data)

複製程式碼

然後寫一個工具類,用於直接運算元據庫(這種設計並不規範,只是為了快速演示)

#db_util.py
def get_toast_info():
    db = pymysql.Connect(
        host='xxx',
        port=3306,
        user='xxx',
        passwd='xxx',
        db='xxx',
        charset='utf8'
    )
    cursor = db.cursor()
    sql = "select content   from   guohe_lite_toast   order   by   id   desc   limit   1 "
    try:
        cursor.execute(sql)
        result = cursor.fetchone()
        return response_info.success('小程式通知查詢成功', result)
    except:
        return response_info.error('2', '小程式通知查詢失敗', result)
        # 關閉資料庫連線
    finally:
        db.close()
def update_toast(toast_update_info):
    db = pymysql.Connect(
        host='xxx',
        port=3306,
        user='xxxx',
        passwd='xxx',
        db='xxxx',
        charset='utf8'
    )
    cursor = db.cursor()
    sql = "insert into guohe_lite_toast(content,update_time) values(%s,%s) "
    try:
        dt = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        cursor.execute(sql,(toast_update_info,dt))
        db.commit()
        return response_info.success('通知更新成功', toast_update_info)
    except:
        db.rollback()
        return response_info.error("2",'更新失敗', toast_update_info)
    finally:
        db.close()
複製程式碼

現在,讓我們使用postman來測試一下介面。

首先更新一下通知:

兩小時快速構建微信小程式

然後看能不能成功獲取:

兩小時快速構建微信小程式

這一切都生效了,資料介面已經準備就緒。

資料渲染

那麼,現在如何在小程式端獲取資料並顯示呢?我們去簡要讀下小程式的官方文件

兩小時快速構建微信小程式

請注意,小程式是純非同步方式來傳送請求的。

依葫蘆畫瓢,我們來模仿一下:

#index.js
wx.request({

      url: 'https://example.com/getToast',
      method: 'GET',
      header: {
        'content-type': 'application/x-www-form-urlencoded' // 預設值
      },
      success: function (res) {
        var message = res.data.info[0]
        console.log(message)
        that.setData({
          toast: message
        })
      }

    })
複製程式碼

我們將獲取的資料已經儲存在"toast"這個變數中了,再去讀文件,看看小程式是如何進行資料繫結的。然後我們將之前寫死的文字換成"{{toast}}",這時再重新整理,可以看到,資料已經顯示了。

<!-- index.wxml -->
<view class="main-card">
 <view class="main-card-item" id="toast" wx:if="{{news_flag}}">
    <view class="card-item-hd" >
      <image class="card-item-icon" src="/images/index/toast.png"></image>
      <text class="card-item-name">大事兒</text>
    </view>
    <view class='toast'>
    {{toast}}
    </view>
  </view>
</view>
複製程式碼

兩小時快速構建微信小程式

此時,一套完整的流程已經結束,雖然實現了一個微小的功能,但麻雀雖小,五臟俱全。接下來,就是去進一步學習,去如何改造以及豐富我們的專案了。

比如稍微努力一下:

兩小時快速構建微信小程式

掃一掃,關注公眾號

相關文章