jQuery 前後端分離專案總結

愚坤發表於2019-03-03

文件目錄

  • 前言
  • 設計階段
    1. 文件
    2. Restful api
    3. 技術選型
  • 開發階段
    1. 本地開發與聯調
    2. 路徑、介面狀態、登入超時、伺服器報錯
    • 統一處理返回結果 登入超時、字串錯誤、其他字串
  • 部署測試階段
    1. 專案根目錄
    2. 自動部署
  • 待解決問題
    1. 路由問題
    2. 狀態共享
    3. 介面測試

前言

近兩年嘗試了一些前後端分離的專案,開發流程和效率上並不是順風順水,效率與質量沒有特別顯著的提升,不過大部分是一些舊專案的維護和二期開發,架構上很難按照單頁面應用的開發模式實現,期間也遇到很多問題,最近在舊的專案上用jquery做了一個小模組的前後端分離,並做了一下記錄和總結。希望多學習多提升,如果有好的實現方法大家能多多指點。

設計階段

1. 文件

在之前的開發與本次的開發,總會遇到的一個問題就是文件,前端用的是淘寶開源的RAP視覺化介面管理工具, 搭建在我們自己的伺服器上,前端定義介面是按照頁面來劃分,一個頁面對應的有幾個介面全部列在頁面名稱下,

jQuery 前後端分離專案總結

但是經過幾個專案的實踐下來,發現java團隊的分工與前端不同,是按照功能實現來分的,前端開發一個購買的流程,會分幾個頁面,第一步,第二步,第三步,再根據每個頁面功能呼叫介面,編表單、校驗等業務邏輯開發,而後端是按照功能劃分,比如前端的第一步、第二步、第三步這個三個頁面都有獲取對應A\B\C列表的介面,開發上僅僅是從庫裡查一下這個欄位再返回給你,那麼類似的功能,就會分給一個java工程師來做,對於後端效率高,介面實現上不會太分散。

jQuery 前後端分離專案總結

所以導致介面文件有兩份,後端用Excel維護一份,前端用RAP維護一份,前端開發開始前要根據後端提供的介面文件按照頁面劃分介面定義mock資料。開發期間偶爾介面一個欄位的變更就需要維護兩份,很不方便,效率反而下來了。

2. Restful api

定義介面要考慮到多種情況,同時要做好規則約束,我們遇到的僅僅幾個,簡單列一下。

狀態碼: 介面報錯有很多種情況,資料格式、伺服器出錯等,要設計好對應提示的資訊和狀態碼。

jQuery 前後端分離專案總結

提交資料型別 ajax提交資料時一般都為json,屬性不能是陣列,我們內部約定,文件可寫陣列,提交時統一將陣列轉為字串。

屬性與陣列 文件內所有返回值,標為list的即返回陣列,沒有標識的即返回屬性。

返回資料型別 我們沒有做的特別細,所以返回的型別都是字串,前端需要統一處理成自己需要用的格式。

所有入參增加params 見程式碼

$.ajax({
        url: "separationCommon/getDic.gsp",
        type: "POST",
        dataType: "JSON",
        baseUrl: true,
        async: false,
        data: {
            "params.dicCode": !code ? "DIC_EB_APPNTPROVINCE": code,
            "params.searchType": 1
        },
        success: function (data) {
            if(data.status == 200) {
                var ARR = data.data.dicList;
                window.STR = provinceSelect(ARR, code);
            }
        }
    });
複製程式碼

3. 技術選型

考慮到開發完以後要交給java團隊自己來維護,我們之前有用過vue和avalon,但是後端人員維護起來很麻煩,就直接用jquery+jquer.tmpl了。jquer.tmpl學習成本幾乎可以忽略不計,另一方面因為是舊的專案,前端幾乎成型,左側是樹選單,右側是load進來的jsp頁面,我們就直接使用jquery的load來載入HTML檔案了。

jQuery 前後端分離專案總結

開發階段

1. 本地開發與聯調

mock工具有請求攔截的外掛,可以直接實現返回資料,RAP官網文件

jQuery 前後端分離專案總結

但是後期聯調也需要轉發和攔截,而且還有登入模擬,就沒有用,直接用express+http-proxy-middleware做的本地轉發

const express = require('express');
const timeout = require('connect-timeout');
const proxy = require('http-proxy-middleware');
const request = require("request");
const cheerio = require("cheerio");
const app = express();

// 超時時間
const TIME_OUT = 30 * 1e3;

// 設定埠
app.set('port', '8080');

// 設定超時 返回超時響應
app.use(timeout(TIME_OUT));
app.use((req, res, next) => {
  if (!req.timedout) next();
});

proxyOption = {
    target: 'http://ipaddress/mockjsdata/6',
	// target: 'http://ipaddress:9527/eb/',
	pathRewrite: {
        '^/api/' : '/'  // 重寫請求,api/解析為/
    },
    changeOrigin: true,
    headers:{
        'Cookie': ''
    }
};


// 靜態資源路徑
app.use('/', express.static('src/page'));

request('http://192.168.180.87:9527/eb/syEdor/moniLongin.gsp', function(err,res,body){
    // 獲取cookie
    var str = res.headers['set-cookie'][0];
    // 設定cookie
    proxyOption.headers = {
        'Cookie':str
    };

    if (!err && res.statusCode == 200) {

        // 反向代理
        app.use('/api/*', proxy(proxyOption));

    }else{
        console.log('登入失敗')
    }
});


// 監聽埠
app.listen(app.get('port'), () => {
  console.log(`server running @${app.get('port')}`);
});

複製程式碼

2. 路徑、介面狀態、登入超時、伺服器報錯

統一專案根路徑 新增部分ajax攔截,判斷條件為options.baseUrl;

jQuery 前後端分離專案總結

 // 專案路徑攔截
    $.ajaxPrefilter(function (options) {
        if(options.baseUrl) {
            if(options.url.indexOf('/eb/') != -1) {
                options.url = options.url;
            } else {
                options.url = '/eb/' + options.url;
            }
            options.crossDomain = false;
        }
    }); 
複製程式碼

介面狀態、登入超時、伺服器報錯 因為報錯有很多種情況,正常的介面返回的狀態碼判斷,如果非200則統一提示, 登入目前沒有用單頁token機制,部分還是會跳轉到jsp,部分介面報錯如500錯誤也會返回jsp,jsp的返回結果是html,也要增加判斷,請求頭內會攜帶session超時資訊。

//ajax請求結束
    $(document).unbind('ajaxComplete').bind('ajaxComplete', function(e,xhr,opt){

        if(opt.baseUrl){
            var str = xhr.responseText;
            try {

                var obj = JSON.parse(str);
                if(obj.status != 200) {
                    popUp(obj.msg);
                }

            } catch(e) {
                // 通過XMLHttpRequest取得響應頭,sessionstatus
                var sessionstatus = xhr.getResponseHeader('sessionstatus');
                if(sessionstatus == "timeout"){

                    popUp('登入超時,請重新登入', function(){
                         window.location.reload();
                    });
                }else if(sessionstatus == "perror"){

                     popUp('請求的連結地址可能存在非法字元', function(){
                         window.location.reload();
                    });
                }else{
                    popUp('404,伺服器出錯!')
                }
            }
        }
      
    });
複製程式碼

部署測試階段

1. 專案根目錄

本地開發和除錯與測試伺服器的靜態資源鏈目錄不一致,頁面中有一些圖片和html檔案的路徑,用gulp打包替換。

 gulp.task('prod:narrowImg', ['prod:narrowJs'], function () {
        return gulp.src(Config.html.htmlProphaseLoad)
            .pipe(replace(/src=\"\.\.\/images/g, "src=\"\/eb\/static\/images"))
            .pipe(replace(/\/api\//g, "\/eb\/"))
            .pipe(replace(/load\(\$\(\"#loadjsp\"\)/g, 'load("\/eb"+$("#loadjsp")'))
            .pipe(rename({dirname: ''}))
            .pipe(gulp.dest(Config.html.distProphaseLoad)); // 替換三期load圖片路徑
    });
複製程式碼

2. 自動部署

gulp-sftp 很好用,直接配置一個任務就可以了。

gulp.task('ftp', function () {
        return gulp.src('dist/一二期/三期/load/*.*')
            .pipe(sftp({
                host: 'ipaddress',
                user: 'user01',
                pass: 'password',
                remotePath: '/application/apache9527/apache/htdocs/eb/load'
            }));
    })
複製程式碼

待解決問題

  1. 路由問題 本來想使用jQuery Hashchange或jqueryRouter來實現的,考慮到之前的模式和開發時間,就沒有來替換。
  2. 狀態共享 目前左右跨頁面的狀態都放在隱藏域的value和div的attr上,後期考慮引入Mbox做狀態管理
  3. 介面測試 前端聯調中,一大部分時間做了介面測試的工作,希望能夠找到好的介面測試工具和測試流程。

才疏學淺,如有問題懇請斧正。

相關文章