深入了解前端控制器之前,先拋出一個問題:控制器是什么?別被控制器這個名字嚇住。其實和原生 Servlet 開發(fā)中開發(fā)者自定義的 Servlet 的功能是一樣的。當然,因為有 Spring 的加持,使用起來,是非常之輕量級的。Spring MVC 中的控制器有 2 類:中央控制器,或叫前端控制器: 由 Spring MVC 框架提供,對所有請求進行分流;用戶控制器,或叫響應控制器: 由開發(fā)者實現(xiàn),用來響應用戶的具體請求。如登錄請求、注冊請求……前端控制器(DispatcherServlet)是 Spring MVC 中最核心的組件,相當于整個程序中的行政、調度中心。其它的組件都是它的附庸,為前端控制器提供相關的服務。Tips: DispatcherServlet 必須在 Spring MVC 項目啟動時被創(chuàng)建。DispatcherServlet 的純 JAVA 配置請查閱《純 JAVA 搭建 Spring MVC 項目》章節(jié)內容。DispatcherServlet 的基本功能。
前端框架如 Vue 打包出來往往是靜態(tài)的文件 index.html 加上一個 static 目錄。static 目錄下有 fonts、css、js、img等靜態(tài)資源目錄。前端的訪問是從 index.html 開始的。假設服務器上打包出的前端代碼放到/root/test-web目錄下,對應部署前端的配置如下:...http{ server { # 監(jiān)聽8080端口 listen 8080; # 指定域名,不指定也可以 server_name www.xxx.com; # 瀏覽器交互調參,打開gzip壓縮、緩存等等 gzip on; ... location / { root /root/test-web; # 也可以簡單使用 index index.html try_files $uri $uri/ /index.html; } # vue 頁面中向后臺 java 服務發(fā)送請求 ... }}...
前后端分離這種概念和技術,早就流行多年了。具體點說,前端編寫 HTML 頁面,然后通過 Ajax 請求后端接口;后端把接口封裝成 API ,返回 JSON 格式的數(shù)據(jù);前端接收到 JSON 返回數(shù)據(jù)后渲染到頁面。前端工程師根本不需要懂后端,調用后端接口就行。后端使用 Spring Boot 控制器返回 JSON 十分簡單,給方法添加個注解,就能將返回值序列化為 JSON 。前端干前端的活,后端干后端的活,職責分明,界限明確。這就是前后端分離的好處啊!
在理解這兩種 Web 應用模式之前,我們需要先明確前端與后端的概念。前端負責頁面的渲染、數(shù)據(jù)的展示,而后端負責處理用于展示的數(shù)據(jù)。通俗地講,前端就是用戶可以看到的東西,比如在一個天氣預報頁面中,用戶所能看到的天氣信息就是前端展示的。每天的天氣不同,展示的數(shù)據(jù)也不一樣,那么這些數(shù)據(jù)從何而來?答案是后端。我們之所以能看到實時更新的天氣數(shù)據(jù),是因為前后端配合作業(yè)實現(xiàn)的。后端在數(shù)據(jù)庫查詢相應時間的天氣情況,查到數(shù)據(jù)后,進行相應的處理、包裝,交由前端,前端獲取數(shù)據(jù)后,根據(jù)提前設計好的樣式,在相應位置填充后端發(fā)來的數(shù)據(jù),這樣一個天氣預報頁面就呈現(xiàn)在了用戶眼前。天氣預報頁面
前后端分離開發(fā),實際上前端工作就簡化了。我們直接新建項目文件夾 shop-front (商城前端項目文件夾),然后將前端頁面放到該文件夾即可。注意該頁面不需要放到 Spring Boot 項目目錄下,隨便找個目錄放置即可。實際開發(fā)過程中,后端和前端的項目可能都不在一臺計算機上。前端核心業(yè)務代碼如下,由于前端技術不是本節(jié)介紹的重點,所以不再詳細解釋,感興趣的同學可以從 Git倉庫 查看完整代碼 。實例: //初始化方法 $(function () { var row = ""; $.ajax({ type: "GET", url: "http://127.0.0.1:8080/goods", //后端接口地址 dataType: "json", contentType: "application/json; charset=utf-8", success: function (res) { $.each(res, function (i, v) { row = "<tr>"; row += "<td>" + v.id + "</td>"; row += "<td>" + v.name + "</td>"; row += "<td>" + v.price + "</td>"; row += "<td>" + v.pic + "</td>"; row += "</tr>"; $("#goodsTable").append(row); }); }, error: function (err) { console.log(err); } }); });開發(fā)完該頁面后,直接使用瀏覽器雙擊打開,查看控制臺發(fā)現(xiàn)有錯誤信息提示。瀏覽器控制臺返回錯誤信息考驗英文水平的時候到了!關鍵是 has been blocked by CORS policy ,意味著被 CORS 策略阻塞了。我們的前端頁面請求被 CORS 阻塞了,所以沒成功獲取到后端接口返回的數(shù)據(jù)。
前端應用的部署更加簡單,我們直接在云服務器上下載 nginx 然后解壓。打開網址 http://nginx.org/en/download.html ,點擊下圖中的鏈接下載即可。nginx 下載鏈接下載解壓后,將前端頁面直接放到 nginx/html 目錄下即可。當然如果有很多網頁,可以先在該目錄下建立子目錄便于歸類網頁。我們建立 shop-front 目錄(表示商城系統(tǒng)的前端項目),然后將網頁放入其中,效果如下:商城系統(tǒng)前端項目目錄內容注意還需要修改 goods.html 中訪問的后端 URL 地址,假設云服務器的公網 IP 為 x.x.x.x ,則修改為:實例:$.ajax({ type: "GET", url: "http://x.x.x.x:8080/goods", //后端接口地址 dataType: "json", contentType: "application/json; charset=utf-8", success: function (res) { $.each(res, function (i, v) { row = "<tr>"; row += "<td>" + v.id + "</td>"; row += "<td>" + v.name + "</td>"; row += "<td>" + v.price + "</td>"; row += "<td>" + v.pic + "</td>"; row += "</tr>"; $("#goodsTable").append(row); }); }, error: function (err) { console.log(err); } });此處解釋下后端地址 http://x.x.x.x:8080/goods , HTTP 代表協(xié)議, x.x.x.x 代表云服務器公網地址, 8080 是我們后端項目的啟動端口,由于我們沒有在配置文件中設置,所以默認就是 8080 ,最后 goods 是控制器中設定的后端接口路徑。雙擊 nginx.exe 啟動 nginx ,由于 nginx 默認啟動端口是 80 ,所以此時訪問 http://x.x.x.x ,效果如下,說明 nginx 啟動成功!nginx 已啟動成功
在前后端不分離的應用模式中,前端向 Web 服務器發(fā)送請求,Web 服務器根據(jù)請求內容,從數(shù)據(jù)庫查詢相應數(shù)據(jù),將數(shù)據(jù)填充進模板渲染,渲染結果發(fā)回前端進行展示。在過去,人們訪問互聯(lián)網幾乎都是通過 PC 瀏覽器,因而僅需開發(fā)適應 PC 顯示的單終端頁面(只在一種設備上使用,其他設備不使用或很少使用的頁面)即可。如果僅開發(fā)單終端的網頁應用,前后端不分離模式是較為普遍的開發(fā)模式,針對同一個頁面,后端提供資源填充入前端模板相應的位置并渲染,展示給客戶即可,無需考慮不同終端需要不同的數(shù)據(jù)類型、不同的展示效果。在這種場景下,前后端不分離模式不僅開發(fā)速度快,還便于開發(fā)人員直接調試頁面。然而隨著移動互聯(lián)網的發(fā)展,Web 應用不再單單服務于 PC 端,同樣的內容需要在不同的終端進行展示。而不同終端需要不同的渲染方式,如果仍然采用前后端不分離的應用模式,就需要后端為不同的前端渲染不同的頁面進行適配,此時增加了許多冗余工作。前后端不分離模式示意圖
網頁有一個最優(yōu)秀的特點就是它的跨平臺性,一個前端程序員寫出的頁面,既可以運行在 Windows 的瀏覽器上、也可以運行在 MacOS 的瀏覽器上、還可以運行在 IOS 和安卓瀏覽器上。正是由于網頁所具備的優(yōu)異跨平臺性擴展出了套殼網頁的這種形式,比如看起來只是個 apk 的安卓程序,點擊也能安裝到手機中,但實際上里面的內容都是網頁…還有現(xiàn)在紅極一時的小程序,其實在很早以前小程序就已經火起來了,但這次疫情真的是把小程序徹底推向了一個巔峰:去商場要掃小程序二維碼、坐高鐵要掃小程序二維碼、去麥當勞要用小程序點餐、去景點參觀要用小程序預約、去看電影要用小程序訂票…那么小程序其實是和前端技術是分不開的,雖然騰訊覺得自己搞的東西不能叫HTML、CSS,取而代之的是 WX(微信)ML、WX(微信)SS… 但其實還是換湯不換藥,語法什么的都基本一致,好多東西甚至連名稱都沒改。而且我們現(xiàn)在做小程序也有那種多端小程序框架:uni-app、mpvue、taro等…這里用的都是 CSS 而不是 微信SS 。所以學會了移動端布局,不僅僅可以把學到的知識運用到移動端的網頁上、還可以用到 React Native、小程序、快應用、Weex等這些前端演變出來的技術上。
微前端 尚處在發(fā)展時期,其核心概念和 微服務 相似?,F(xiàn)階段較為常用的微前端框架為 single-spa 和 qiankun,后者是基于前者實現(xiàn)的。該技術能做到 技術棧無關,即一個應用,能由多個不同技術的子應用構成,同時做到子應用的相互隔離,這里的隔離就可以選擇采用 Web Components 實現(xiàn)。
可以使用 Request 對象中的 port() 方法獲取當前訪問的端口號,代碼如下: public function getInfo(Request $request){ halt($request->port()); }執(zhí)行結果如下圖所示:Tips: 所謂的端口,就好像是門牌號一樣,客戶端可以通過ip地址找到對應的服務器端,但是服務器端是有很多端口的,每個應用程序對應一個端口號,通過類似門牌號的端口號,客戶端才能真正的訪問到該服務器。為了對端口進行區(qū)分,將每個端口進行了編號,這就是端口號 。
前端的安全主要圍繞 W3C 進行,同時瀏覽器的漏洞和 Http 協(xié)議本身的缺陷也會造成影響。
在前后端分離的 Web 應用中,后端此時扮演的角色只是提供前端所需的數(shù)據(jù),不再負責樣式的渲染。前端的展示樣式,完全由前端負責,針對不同的終端,進行不同的渲染,這樣不僅提高了用戶體驗,還在很大程度上降低了前后端的耦合度。由于不同終端所需的數(shù)據(jù)幾乎一樣,后端僅需專注于業(yè)務邏輯,為前端提供數(shù)據(jù)即可,不再需要適配不同終端,提供不同頁面,這便大大降低了開發(fā)工作量。在前后端分離的應用模式中,我們通常將后端開發(fā)的每個視圖都稱為一個接口,或者API,前端通過訪問接口來對數(shù)據(jù)進行增刪改查。前后端分離模式示意圖
在學習Socket編程之前我們要了解一下概念。端口不是物理設備,而是促進服務器和客戶端之間通信的抽象概念。端口是由一個 2 的 16 次冪的整數(shù)表示的,所以,一臺機器最多可以有65536個端口(0~65535)。端口一共分為三個種類:知名端口:0 ~ 1023(例如:80端口用于http,25端口用于smtp)。注冊端口:1024 ~ 49151。動態(tài)/私有端口:49152 ~ 65535。
將宿主機的本地端口,與指定容器的服務端口進行映射綁定,之后訪問宿主機端口時,會將請求自動轉發(fā)到容器的端口上,實現(xiàn)外部對容器內網絡服務的訪問。創(chuàng)建名為 n0 的 nginx 容器,映射宿主機 8000 端口到它的 80 端口docker run -d -t -p 8000:80 --name n0 nginxTips:指定的宿主機端口必須是未被占用的端口,否則操作會失敗,且生成一個無法正常啟動的容器 n0, 需要手動刪除。使用 docker port n0 查看 n0 的端口映射信息,顯示如下:80/tcp -> 0.0.0.0:8000打開瀏覽器,地址欄輸入 http://localhost:8000 或 http:// 宿主機 IP:8000, 都能訪問到 n0 的 nginx 服務。如果需要綁定多個容器端口,可以連續(xù)使用 -p 參數(shù)多次指定docker run -d -t -p 8001:80 -p 8433:443 --name n1 ngin如果不想主動指定宿主機端口,可以使用 -P 參數(shù),宿主機隨機使用一個可用端口與容器端口進行映射docker run -d -t -P --name n2 nginx如果只想使用宿主機上特定的網口與容器進行映射docker run -d -t -p 192.168.1.13:8002:80 --name n3 nginxTips:此處 192.168.1.13 指代 宿主機映射網口的 IP 地址,需要根據(jù)網口的實際 IP 更改 *。我們執(zhí)行 docker ps 可能出現(xiàn)如下幾個的 nginx 容器:再執(zhí)行 iptables -t nat -nL 查看下防火墻:比對上面兩個的輸出,不難發(fā)現(xiàn),這種端口轉發(fā)方式的本質是通過配置 iptables 規(guī)則轉發(fā)實現(xiàn)的,效率較低,如果容器的服務端口數(shù)量過多,需要配置較多的映射,占用大量宿主機端口,也不便于管理。不再使用的容器記得刪除掉,釋放資源和空間docker rm -f n0 n1 n2 n3
前言:大家好,很高興和大家又見面啦!之前得幾個小節(jié),主要給大家介紹了 Yarn 的相關知識和使用技巧。我們知道,前端這個技術棧,是近幾年前后端分離的這個天才思路出現(xiàn)后,才得以迅猛發(fā)展,在日常的開發(fā)中扮演著越來越重要的角色。前人說:工欲善其事必先利其器。前端的發(fā)展,離不開眾多優(yōu)秀的工具,本文將以橫向對比的思路,帶大家認識一下市場上主流的,跟 yarn 的地位差不多的各種依賴管理工具。
本節(jié)主要介紹 Spring Boot 中 JdbcTemplate 的用法,所以前端頁面僅給出代碼和注釋,不再進行詳細介紹了。前端只有一個頁面,使用 Bootstrap 的樣式和插件,通過 jQuery 的 $.ajax 方法訪問后端接口,邏輯并不復雜。此處簡單展示下瀏覽商品部分的前端代碼,感興趣的同學可以從 Git倉庫 查看完整代碼。實例: //瀏覽商品 function viewGoods() { var row = ""; //先清空表格 $('#GoodsTable').find("tr:gt(0)").remove(); $.ajax({ type: "GET", url: "http://127.0.0.1:8080/goods", dataType: "json", contentType: "application/json; charset=utf-8", success: function (res) { console.log(res); $.each(res, function (i, v) { row = "<tr>"; row += "<td>" + v.id + "</td>"; row += "<td>" + v.name + "</td>"; row += "<td>" + v.price + "</td>"; row += "<td>" + v.pic + "</td>"; row += "<td><a class='btn btn-primary btn-sm' href='javascript:editGoods(" + v.id + ")' >編輯</a>"; row += "<a class='btn btn-danger btn-sm' href='javascript:removeGoods(" + v.id + ")' >刪除</a></td>"; row += "</tr>"; console.log(row); $("#GoodsTable").append(row); }); }, error: function (err) { console.log(err); } }); }
當一個 HTTP 請求打進服務器之后,一般的流程是:網關層(例如Ngnix)最先獲取請求,然后路由轉發(fā)到具體的Web服務,經過一段業(yè)務邏輯之后,可能還會查詢數(shù)據(jù)庫,最后將處理的結果返回給瀏覽器客戶端。對于后端開發(fā)程序員來說,日常的工作就集中在服務器端,特別是流程圖中的"Web業(yè)務服務"這塊,例如基于 Spring 框架、Django 框架或者ThinkPHP 框架進行業(yè)務邏輯開發(fā)和上線。(HTTP 請求進入服務器端后的解析流程圖)
接下來講到的一種是服務端代理的方式。要問為什么采取服務端代理的方式呢?很簡單,因為瀏覽器端 Ajax 請求有跨域的限制,那我們就把請求不同域的操作放在服務端好了,畢竟服務端是沒有跨域限制這一說的。3.2.1 服務端代理原理瀏覽器端發(fā)送請求到同域的服務端;服務端接收到請求之后,進行轉發(fā),請求不同域的另外一個服務端;服務端間進行交互數(shù)據(jù)后,同域服務端返回數(shù)據(jù)給瀏覽器端。3.2.2 具體例子舉一個服務端代理的例子,這里我使用了一個 Express 的中間件,叫做 express-http-proxy 。當然同學們也可以在同域服務端接收到請求的時候,發(fā)起 http 請求訪問不同域的服務端來模擬這一代理行為。前端方面我使用了 jQuery 的 Ajax 方法。3.2.2.1 javaScript 關鍵代碼$.ajax({ url: '/proxy/proxy_get', method: 'GET', data: { a: '123', b: '234' }}).done(data => { console.log(data)})很簡單,我們就是向同域的服務器發(fā)送了一個請求。3.2.2.2 同域服務器關鍵代碼const proxy = require('express-http-proxy'); // 引入代理中間件// ... 一些代碼app.use('/proxy', proxy('http://localhost:8082/')); // 注冊,之后 /proxy 都會代理到 http://localhost:8082/ 上3.2.2.3 不同域的服務器關鍵代碼router.get("/proxy_get", function(req, res) { const {a, b} = req.query res.send(`參數(shù)是:${a} 和 $`)});這是目標服務器的響應方法,返回一個 處理后的字符串。3.2.2.4 效果3.2.3 服務端代理小結服務端代理通過服務端和服務端之間的交互來避免瀏覽器和不同域的服務端之間直接進行交互,從而避免了跨域的問題。當然這種方法要求我們有一個中間服務器的存在。
所謂的端口,就好像是門牌號一樣,客戶端可以通過 ip 地址找到對應的服務器端,但是服務器端是有很多端口的,每個應用程序對應一個端口號,通過類似門牌號的端口號,客戶端才能真正的訪問到該服務器。為了對端口進行區(qū)分,將每個端口進行了編號,這就是端口號 。而 MySQL 服務默認指定的端口號為 3306,這個在之前介紹安裝 MySQL 的時候,其中配置 my.ini 文件的內容時候,其中就有端口號配置,內容如下:
http 最常用的協(xié)議,用于客戶端主動向服務器發(fā)送請求,單向傳遞;ajax HTTP 的擴展版,底層還是 HTTP 協(xié)議,只不過客戶端是無刷新的;comet 也是基于 HTTP 封裝的,使用 HTTP 長連接的方式,原理大致是將 HTTP 的timeout 設置較長,服務器有數(shù)據(jù)變化時返回數(shù)據(jù)給客戶端,同時斷開連接,客戶端處理完數(shù)據(jù)之后重新創(chuàng)建一個 HTTP 長連接,循環(huán)上述操作(這只是其中一種實現(xiàn)方式);websocket 這是 HTML5 中的新標準,基于 socket 的方式實現(xiàn)客戶端與服務端雙向通信,需要瀏覽器支持 HTML5;Adobe Flash Socket 這個也是使用 socket 的方式,需要瀏覽器支持 flash 才行,為了兼容老版本的瀏覽器;ActiveX object 只適用于 IE 瀏覽器;目前尚沒有一種方式能兼容所有的瀏覽器,只能針對軟件的目標客戶人群做一定的兼容。sse 服務端單向推送。
Nginx 作為 Web 服務器能獨立提供 Http 服務。另外,我們常常通過 Nginx 作為靜態(tài)資源服務器來訪問服務器上的靜態(tài)資源,比如對于最新熱門的前后端分離架構,前端打好包后直接放到某個地址,在 Nginx 配置后可以通過 Nginx 來訪問主機上的前端頁面。
在 Web 應用中,用戶通過瀏覽器向服務器提交請求,服務器接收到請求后,對用戶的請求進行處理,再將結果返回給用戶。例如,使用 baidu 搜索引擎的過程如下:用戶在 baidu 的搜索框中,輸入關鍵字 “手機”,瀏覽器將關鍵字 “手機” 發(fā)送到 baidu 的服務器。baidu 服務器收到查詢手機的請求,在數(shù)據(jù)庫查找和手機相關的網頁,按照與關鍵詞的相關性進行排序,再將排序結果發(fā)送給用戶。瀏覽器收到服務器的查詢結果后,顯示與 “手機” 相關的網頁列表。在以上的 3 個步驟中,與用戶交互的部分稱之為前端,在服務器處理的用戶請求的部分稱為后端。Python 提供了大量的模塊和框架可以用于后端開發(fā)。有很多知名的網站后端采用了 Python,例如,國內的豆瓣就是一個應用Python打造的非常成功的 Web 2.0 站點。
待做清單程序的總體結構分為前端和后端兩個部分,上一節(jié)介紹了后端的實現(xiàn),本節(jié)講解前端的實現(xiàn)。
使用瀏覽器訪問網站的過程如下所示:瀏覽器向網站發(fā)出請求網站收到請求后,返回 HTML 文本作為響應內容在下圖的例子中,服務器返回當前時間 (HTML 的格式)。使用瀏覽器訪問網站時,顯示的內容是動態(tài)的,每次都是當前時間,如下所示:在這個例子中,瀏覽器又被稱為前端,服務器又被稱為后端。后端收到請求后,做如下的工作:分析用戶請求,獲取請求的參數(shù)根據(jù)請求的參數(shù)進行處理,可能會讀取數(shù)據(jù)庫最終生成一段 HTML 文本返回給前端Python 作為一個通用的編程語言,能夠完成以上的工作,由于其開發(fā)效率高,在 Web 后端開發(fā)中占有重要的一席之地。以下是慕課網的課程分類目錄,在后端開發(fā)的分類中,Python 和 Django (Python 的 web 框架) 占有兩個條目:
前面介紹了如何安裝虛擬機,還介紹了如何在虛擬機上安裝 CentOs 操作系統(tǒng),并且給 CentOs 配置了局域網固定 ip,那么此時的 CentOs 相當于是在局域網的一臺服務器了,虛擬機上面已經自帶終端工具,實際業(yè)務中使用較多的是終端工具連接遠程服務器,較為常見的 Linux 服務器終端連接工具有 xshell、MobaXterm、putty 等等。其中 MobaXterm 對個人免費使用,且功能齊全,本小節(jié)介紹如何安裝 MobaXterm。
上面我們講了在 Ruby 環(huán)境中安裝 Sass ,但我們前端在 Ruby 環(huán)境下開發(fā)是非常少的,我們前端現(xiàn)在基本都使用 Webpack 構建,一般都是在 Node 環(huán)境開發(fā),那在前端項目里是如何安裝 Sass 呢?首先你要知道 node-sass 和 dart-sass ,這兩個都是提供好的類庫,是 Sass 的實現(xiàn),本身 Sass 是使用 Ruby 語言寫的,但是它提供了很多接口以方便其他語言來集成和封裝,node-sass 和 dart-sass 就是基于 LibSass( Sass 的 C 版本) 封裝而來的。它們和 LibSass 的關系就是橘子和橘子汁的關系,我們前端基本也都是通過這兩個庫來使用 Sass ,我們畫個圖來看下它們的關系:本章節(jié)我們以 node-sass 為例,本教程中所有的內容都是以 node-sass 為例的。
同樣,我們展示了通過 C 語言 Socket API 編寫 UDP 客戶端和服務器程序的步驟,如下:圖中的矩形方框都是 C 函數(shù)。對比 TCP 客戶端、服務器的建立過程,我們發(fā)現(xiàn) UDP 客戶端可以調用 connect 函數(shù),但是并不會去連接服務器,只是和本地接口做綁定;UDP 服務器是沒有 listen 和 accept 調用的。對于 UDP 客戶端來說,connect 函數(shù)的調用是可選的。接下來,我們就探討一下如何用 Java 語言編寫 UDP 客戶端和服務器程序。
客戶端,是指發(fā)起請求的一方。也就是瀏覽器,或者指爬蟲程序。通過發(fā)起請求,來獲取想要的網頁。服務端,請求的響應端,是 web 服務端。web 服務,是一個虛擬意思上的機器的概念。可以是一個計算機集群,也可以是一個軟件或者程序??蛻舳?,通過發(fā)送一個請求給服務端,然后進行等待。服務端按照客戶端的請求,返回客戶端需要的數(shù)據(jù)。這個過程,我們稱之為經典的客戶端——服務端模型。
在互聯(lián)網早期,網站的內容都是一些簡單的、靜態(tài)的頁面,服務器后端生成網頁內容,然后返回給瀏覽器,瀏覽器獲取 html 文件之后就可以直接解析展示了,這種生成 HTML 文件的方式被稱為服務器端渲染。而隨著前端頁面的復雜性提高,出現(xiàn)了基于 ajax 技術的前后端分離的開發(fā)模式,即后端不提供完整的 html 頁面,而是提供一些 api 返回 json 格式的數(shù)據(jù),前端調用后端的 API 獲取 json 數(shù)據(jù),在前端進行 html 頁面的拼接,最后后展示在瀏覽器上,這種生成 HTML 文件的方式被稱為客戶端渲染。簡單的使用 requests 庫無法爬取客戶端渲染的頁面:requests 爬下來的頁面內容并不包含真正的數(shù)據(jù)只能通過調用后端的 API 才能獲取頁面的數(shù)據(jù)有兩種方式爬取客戶端渲染的網頁:分析網頁的調用后端 API 的接口這種方法需要分析網站的 JavaScript 邏輯,找到調用后端 API 的的代碼,分析 API 的相關參數(shù)。分析后再用爬蟲模擬模擬調用后端 API,從而獲取真正的數(shù)據(jù)。很多情況下,后端 API 的接口接口帶著加密參數(shù),有可能花很長時間也無法破解,從而無法調用后端 API。用模擬瀏覽器的方式來爬取數(shù)據(jù)在無法解析后端 API 的調用方式的情況下,有一種簡單粗暴的方法:直接用模擬瀏覽器的方式來爬取,比如用 Selenium、Splash 等庫模擬瀏覽器瀏覽網頁,這樣爬取到的網頁內容包含有真實的數(shù)據(jù)。這種方法繞過分析 JavaScript 代碼邏輯的過程,大大降低了難度。
用法:EXPOSE 端口號示例:EXPOSE 8080啟動容器時,如果我們使用自動映射 -P 或 --net=host 宿主機網絡模式,容器中 EXPOSE 標記暴露的端口與宿主機網絡會自動建立關聯(lián)。如果沒有指定 EXPOSE,使用 -p 手動指定端口映射參數(shù)也可以訪問到容器內提供服務的端口。EXPOSE 顯式地標明鏡像開放端口,一定程度上提供了操作的便利,也提高了 Dockerfile 的可讀性和可維護性。