爲什麼需要前後端分離?
因爲傳統開發的後臺開發中,後臺工作者需要設計MVC三層,前後端都要懂一點,有點麻煩。
先看一下傳統開發流程:
弊端:耦合度高,一旦出錯不易找錯
耦合度高導致維護性差,開發效率也低
擴展性差,無法兼容其他終端例如app
調試效率低
前後端分離後開發流程
觀察可以發現:
前後端分離後,後臺需要提供一個接口文檔,開發相應的接口。
那接口文檔是個什麼東東呢?
接口文檔:告訴前端:接口地址,參數是什麼,分別是什麼類型,返回值格式,每個key表示什麼含義,下面有例子。
那麼什麼HTTP服務器(靜態資源服務器)?它和tomcat服務器的區別是什麼呢?
HTTP服務器就是隻要能響應HTTP請求即可;
tomcat是servlet容器,可以處理HTTP請求,也能解析執行JSP+servlet
對比我們之前編寫的整個項目結構和部署環境而言,有以下區別:
簡言之,就是在傳統開發上增加了一個服務器處理靜態資源,將View和Controller層放到了前端,後臺僅需處理數據存取相關及業務邏輯相關
前端:負責View和Controller層
後端:只負責Model層,業務處理/數據等。
前後端分離的優缺點
優點:
關注點分離,視圖層和控制層邏輯移到了前端,後端更注重業務邏輯和系統構架
耦合大大降低,開發效率和維護效率都得到提高
錯誤友好,後臺錯誤不影響前臺界面展示
對於開發者,前後端不再需要過多的涉及彼此的開發語言
缺點:
前端開發者壓力更大,需要關注Controller層
增加靜態服務器後,系統結構更復雜
更多的HTTP請求,在移動端運行效率差
邏輯靠近前端,不同平臺需針對性重複實現,(安卓iOS+web)
SEO優化無力,爬蟲大多不支持ajax
爬蟲一般只爬靜態頁面 xx.html
SEO(搜索引擎優化)搜索引擎本質上就是一個爬蟲,seo優化本質就是對爬蟲友好。
重新定義前後端
前後端分離 如何劃分前端和後端?根據職責劃分
前端負責V+C,後端負責 M和Service
前後端分離後,請求次數會變多
前後端分離頁面執行流程(針對瀏覽器)
Controller層中會使用流程控制來完成數據校驗,數據解析,頁面的跳轉等動作,那麼如何完成呢,這就需要使用到JavaScript了
注意:如果前端是其他的例如iOS,安卓,則無需請求靜態頁面,頁面的繪製是由系統原始語言實現的,只需要向後臺請求json數據即可
那麼一個前後端分離的項目,前端是如何完成最終的數據展示呢?上面已經提到,就是json
json
格式簡單
解析方便,跨平臺
輕量級
內容爲字符串
Ajax
Ajax是客戶端的一種請求方式,用於異步的向服務器發送HTTP請求並獲取響應數據。
異步的好處在於,請求期間瀏覽器不會被卡死,可以正常響應用戶操作
而常見的表單提交,和直接打開指定地址,都是同步的。
再次說一下接口文檔:告訴前端:接口地址,參數是什麼,分別是什麼類型,返回值格式,每個key表示什麼含義
下面書寫一個簡單的前後端分離
準備一個接口
package com.cx;
import java.io.IOException;
@javax.servlet.annotation.WebServlet(name = "jsonServlet",urlPatterns = "/jsonServlet")
public class jsonServlet extends javax.servlet.http.HttpServlet {
protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
doGet(request,response);
}
protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
//告訴客戶端,返回值的類型是json
response.setContentType("application/json;charset=utf-8");
//返回的具體數據
response.getWriter().println("{\"name\":\"22我\",\"age\":18}");
}
}
編寫靜態頁面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/jquery-2.1.0.js"></script>
</head>
<body>
<h1>我是主頁</h1>
<script>
$.ajax({
//請求的地址
url:"http://localhost:8080/qianHouDFL/jsonServlet",
//如果請求成功執行的代碼
success:function (data) {
console.log(data);//data是服務器返回的數據
//將返回數據做成一個標籤插入到頁面中顯示
document.body.insertAdjacentHTML("beforeend","<h1>%</h1>".replace("%",data.name));
document.body.insertAdjacentHTML("beforeend","<h1>%</h1>".replace("%",data.age));
},
//如果請求失敗執行的代碼
error:function (err) {
console.log(err);
}
});
</script>
哈哈哈
</body>
</html>
根據訪問路徑http://localhost:8080/qianHouDFL/mine.html得到運行結果
如果將.html拉到外面運行,例如HBuilder(別忘了導入依賴)則會發現頁面上沒有顯示服務器返回的結果….
前後端分離之跨域問題
打開瀏覽器檢查頁面會發現沒有輸出服務器返回的消息而是,出現了一個錯誤信息,這就是前後端分離最常見的跨域問題
跨域就是一個頁面的腳本訪問了一個不屬於當前服務器的資源
跨域是一個動詞,描述的是瀏覽器在解析js時發現js代碼請求了一個不屬於當前服務器的資源,此時就是跨域訪問
默認情況下,跨域訪問是不被允許的,其本質是因爲瀏覽器遵循了一個安全機制叫做同源策略
怎麼判斷是否同源?
ip(主機地址或域名) 端口號 請求協議
同源限制:
無法讀取非同源網頁的 Cookie、LocalStorage 和 IndexedDB
無法向非同源地址發送 AJAX 請求
什麼時候產生跨域問題:
瀏覽器在解析執行一個網頁時,如果頁面中的js代碼請求了另一個非同源的資源,則會產跨域問題
而瀏覽器直接跳轉另一個非同源的地址時不會有跨域問題
解決跨域問題
既然禁止跨域問題是瀏覽器的行爲,那麼只需要設置瀏覽器允許解析跨域請求的數據即可,但是這個設置必須放在服務器端,由服務器端來判斷對方是否可信任
在響應頭中添加一個字段,告訴瀏覽器,某個服務器是可信的
package com.cx;
import java.io.IOException;
/**
*
*/
@javax.servlet.annotation.WebServlet(name = "jsonServlet",urlPatterns = "/jsonServlet")
public class jsonServlet extends javax.servlet.http.HttpServlet {
protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
doGet(request,response);
}
protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
//告訴客戶端,返回值的類型是json
response.setContentType("application/json;charset=utf-8");
//解決跨域問題,在響應頭中明確指出,對方是可信的
//*表示 允許所有來源的跨域訪問 (測試時用,正式部署需要指定爲靜態資源服務器地址)
response.setHeader("Access-Control-Allow-Origin","*");
//返回的具體數據
response.getWriter().println("{\"name\":\"22我\",\"age\":18}");
}
}
其值可以是某個或多個指定的域名,也可以是*表示信任所有地址
其他相關設置
//指定允許其他域名訪問
‘Access-Control-Allow-Origin:http://XXX.XXX.XXX’//一般用法(,指定域,動態設置),注意不允許攜帶認證頭和cookies
//預檢查間隔時間 ‘Access-Control-Max-Age: 1800’ //允許的請求類型
‘Access-Control-Allow-Methods:GET,POST,PUT,POST’ //列出必須攜帶的字段
‘Access-Control-Allow-Headers:x-requested-with,content-type’