前後端分離架構中的介面設計

執法丶大隊發表於2020-04-06

前後端分離一般是指在軟體開發過程中,前端程式碼和後端程式碼分別開發,互不干涉,不使用後端語言去寫前端,也不用前端技術寫後端,從形式上來說,一般是不用JSP或PHP混寫程式碼,但並不是說不能用JSP或php檔案格式。前後端分離後,前後端的通訊一般是通過HTTP介面的方式進行呼叫。 
對與前後端分離的概念有很多人都會有誤解:

  • 前後端分離就不能使用JSP這樣的檔案:
  • 實際上分離並不一定非得用HTML檔案,只要不在JSP寫大量後端程式碼,那麼JSP只是一種檔案字尾而已,它是經過javac預編譯的,需要在web容器裡把編譯好的.class轉成html文件返回給瀏覽器,對瀏覽器來說,拿到的依然是html文件,只不過對於前後端分離的部署方式來說不太方便而已,但絕不是說.jsp檔案就不是前後端分離了,比如我們可以用jsp來獲取專案的basePath,而前端在傳送http請求時就可以知道介面的全路徑了。舉個例子:如果在專案的/app/modules/users/index.html中傳送了一個ajax請求:
$.ajax("getUserList?page=1&limit=20",...)
  • 1
  • 1

這樣發出的請求地址是:

http://serverName:port/projectName/app/modules/users/getUserList&page=1&limit=20
  • 1
  • 1

這樣很容易有一個404錯誤,因為實際上我們的介面路徑是:

http://serverName:port/projectName/getUserList&page=1&limit=20
  • 1
  • 1

那麼如果我們用絕對路徑呢?

$.ajax("/getUserList?page=1&limit=20",...)
  • 1
  • 1

如果你的專案部署在tomcat的根目錄裡(通常是ROOT),那是沒問題,否則的話,實際的請求變成了:

http://serverName:port/getUserList&page=1&limit=20
  • 1
  • 1

這個絕對路徑是相對於tomcat來說了,省略了專案名稱,如果你不是部置在tomcat根目錄裡,仍然會得到一個404錯誤,這裡我們需要配置上專案名稱:

$.ajax("/projectName/getUserList?page=1&limit=20",...)
  • 1
  • 1

這樣是沒問題了,但如果專案中很多ajax請求,在每個地方都要帶上這個專案名稱,一旦有一天,運維告訴你專案部署的projectName改了(有時可能不得不這麼做),那前端工程師的苦逼日子就來了。 
對於單頁面應用還好,可以做一個全域性的配置來儲存這個projectName,這樣,如果有改動也只是改一個地方而已,但對於多頁面應用來說,不可能每個頁面都定義一個js全域性變數,但我們可以藉助Java的能力,使用JSP裡的方法把這個變數動態地寫在頁面裡:

<%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>

<script type="text/javascript" >
var basePath="<%=basePath%>";
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

當然要解決這個問題也還有其他辦法。但這麼做我覺得並不違反前端後分離架構,因為在執行期前端程式碼和後端程式碼仍然是分開的。在JSP裡並沒有使用struts的標籤庫,也沒有呼叫java方法取得資料後生成HTML,資料仍是載入後非同步取的。

  • 前後端分離cookie,session就沒用了

之所以有這個誤解,可能是以為ajax請求會與session沒有關係了,實際上session是管理的會話,只要是同一個會話裡的http請求,不管是請求一個頁面,還是ajax請求個介面,只要是同源並在同一會話,都是屬於一個session裡的,ajax請求到後端後,仍然可以從HttpRequest裡拿到session裡面的資訊。 
前後端分離就是前端只管前端的事,後端只管後端的事,互不干涉 
這句話不算錯,但也不是絕對,在一個專案裡,團隊裡的如果做了前後端的分工,就要配合好去做專案,也許對於全棧工程師來說前後端可以一起搞定,但對於前後端分離的架構來說,同一個功能則需要前端工程師和後端工程師鼎力配合才可完成,分離的好處是為了讓大家專注於做自己擅長的事,是為了讓前端體驗更好後端架構更穩定,讓前端和後端的工程師都有更多精力做更多的測試,讓前端心裡想著頁面,後端想著邏輯,資料庫則做好儲存,沒有好的配合,只想撇清責任,那麼分還不如不分。 
*前後端分離就不能用模板技術了 
對於模板技術來說有後端模板如freemarker和前端模板技術如jade,無論哪種模板,都是為了生成html的,模板是為了把結構抽取出來,讓資料去匹配模板,達到複用的目的,後端模板需要經過編譯,而前端模板則直接返回就可以了,那麼是不是使用了後端模板技術就不是前後端分離了嗎? 
這個和使用jsp還不一樣,實際上如果使用後端模板就類似於在jsp裡寫一些html輸出的程式碼,但寫起來又不一樣,因為模板技術框架一般做了封裝,使得你的資料和模板是分開的,只是在需要的時候才合在一起,而不像jsp裡java與html混寫的方式,一般情況下,為了頁面體驗,即使使用後端模板技術,模板檔案也常是前端工程師或全棧工程師來寫的,不懂前端技術是不可能寫好模板檔案的。 
但不管怎麼樣,從編譯和執行的角度來看,後端模板技術不適合前後端分離的架構,因為ftl之類的檔案並沒有很好的IDE支援,另外把資料隨頁面一次編譯裝配再載入到頁面效能不高,採用ajax使用者可以快速先看到頁面,這比等著一個空白視窗會給人更多愉悅感。


前後端分離架構的介面設計

在前後端分離架構中,前端和後端都專注於自己的技術領域,但要完成功能他們又要很好的配合,這時團隊的作用就很明顯。前後端分離架構更適合大專案,對於人手極為有限的小專案來說,一個人全都搞定最省事,但對於多人的團隊來說,前後端分離要求有更多的溝通,溝通成本會明顯上升,要知道溝通一多,矛盾必然也多,所以大家一起玩就一定要定好規則,沒有規則就會亂糟糟。 
從架構上來說,前端要溝通的最多的無非是需求和介面,前端需要比照著原型圖、設計圖來做,因此常與產品經理和設計師溝通,另外前端需要很多資料介面,這需要後端的支援,想像一下,如果團隊裡有五個前端五個後端,如果沒有很好的介面規範與溝通模式,那麼這五個前端常常需要去找後端看介面,比如加一個引數,或某個值傳的不對,或者前後端定的不統一,或者資料格式沒商量好等,那麼後端工程師哪還有時間寫程式碼?而前端工程師也要花費很多口舌。 
今天我們不談前端與UI或需求的溝通,因為大多情況下原型圖的格式各個公司都差不多,而每個公司甚至團隊的介面文件(後端提供的介面說明)可能千差萬別,有很多還沒有文件,兩個人商量好了,程式碼也寫了,如果某一天又來了個新人,那全蒙了,他需要看懂前端程式碼和後端程式碼甚至資料庫,再結合需求文件,再與若干人做一系列溝通才有可能弄懂到底是怎麼實現的,如果團隊的人更多,則情況會更復雜,尤其一專案裡只有一個後端,有好幾個前端的情況下,沒有好的文件,一堆人去找這個後端問,情況可想而知。 
實際工作中大家用的最多的文件是word、Excel、txt,我覺得這幾種格式都很不好,word多人編輯不方便,而且修改起來麻煩,excel和txt我覺得純屬應付,根本不適合做介面文件。 
也有很多公司在這方面做的很好,如開發了一個解決這個問題的系統,或者有錢乾脆去買一個,在有新介面或改動時,直接在系統裡改,大家都看得到。 
對於沒有這樣條件的團隊,我的建議是,不如約定好一種格式,做好規範,減少溝通成本。 
我推薦使用json檔案格式,JSON是一種前後端都支援的很好的資料交換格式,它小巧、輕量、易於處理、易於理解,修改豐收來很容易,而且,等有了時間和精力,可以寫個小程式把JSON轉換成任何你需要的文件格式,比如把json格式的介面文件轉成html釋出到某個網站下,如果你願意,可以讓程式自動地做這件事,只要介面有變更,馬上轉換併發布到網站裡。 
比如,我們可以這麼定義一個介面:

{
    project:'erp',
    basePath:'http://m.co.erp/rest/',
    [{
        name:'獲取使用者列表',
        url:'usr/list',
        author:'唐建國',
        https:false,
        method:['GET','POST'],
        params:[{
            pageNo:'頁碼',
            defaltVal:1,
            required:false,
            type:'int'
        },{
            pageSize:'每頁大小',
            defaltVal:20,
            required:false,
            type:'int'
        }],
        headers:{'content-type':'application/html'},
        response:{
            retCode:{
                name:'返回碼',
                type:'int',
                comment:'1成功,0失敗'
            },
            rows:{
                type:'array',
                comment:'使用者列表資料',
                fields:[{ 
                    account:'帳戶名', 
                    type:'string'
                },{
                    userName:'使用者姓名',
                    type:'string'
                },{
                    age:'年齡',
                    type:'string'
                },{
                    sex:'性別:1男,2女'
                    type:'boolean'
                }]
            }
        },
    }]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

以上只是簡單的寫了一個格式,僅做參考,另外關於這個介面的描述,樣例地址,都可以定義進去,這種方式很容易閱讀,輸入和輸出很清楚,團隊只要商量好,形成規範,以後有了新介面或改了舊介面,只用在這上面改動一下就可以了,而且用大多數的文字工具都可編輯,提交到SVN,Git也容易,想一想,這會減少多少溝通成本呀。

如果你喜歡看html格式的,沒問題呀,寫個程式,無論是java還是js,都可以很容易把上面的內容轉成html文件,再也不用開啟龐大的word來編輯了。

也許你覺得上面說的方式很low,你的公司或專案中已經有了更加高大上的方式,也希望你能分享出來,如果你的團隊在前後端分離架構中遇到了介面設計上的問題,希望上面的思路對你有所啟發,解決問題並不一定要直接弄個高大上的,這種簡單的定義,只要商量好,要省事的多,而且寫這種文件很節省時間,只要寫好一個JSON介面模板,以後直接拷貝下修改幾個欄位,文件就出來了。 
程式設計師何苦為難自己。

相關文章