Web全棧開發學習筆記—Part3 用NodeJS和Express寫服務端程式—b.把應用部署到網上
目錄
Serving static files from the backend
Streamlining deploying of the frontend
接下來,將之前製作的前端連線到我們自己的後端。
前面的部分中,前端可以從作為後端的 json 伺服器向地址 http://localhost:3001/notes 索取便箋列表。
現在後端有一個稍微不同的 url 結構,便箋可以從 http://localhost:3001/api/notes 中獲取到。
修改 src/services/notes.js 中的baseUrl屬性 :
import axios from 'axios'
const baseUrl = 'http://localhost:3001/api/notes'
const getAll = () => {
const request = axios.get(baseUrl)
return request.then(response => response.data)
}
// ...
export default { getAll, create, update }
現在前端的 GET 請求由於某些原因不能工作: http://localhost:3001/api/notes:
但是可以從瀏覽器和Postman訪問後端,沒有任何問題。
Same origin policy and CORS
【同源政策和 CORS】
問題出在一個叫 CORS 的東西上,或者叫跨來源資源共享。
根據維基百科 :
Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources (e.g. fonts) on a web page to be requested from another domain outside the domain from which the first resource was served. A web page may freely embed cross-origin images, stylesheets, scripts, iframes, and videos. Certain "cross-domain" requests, notably Ajax requests, are forbidden by default by the same-origin security policy.
Cross-origin resource sharing (CORS)是一種機制,它允許一個網頁上受限制的資源(例如字型),從提供一手資源的域名以外的另一個域名請求跨來源資源共享。 一個網頁可以自由地嵌入跨來源的圖片、樣式表、指令碼、 iframe 和視訊。 預設情況下,同源安全策略禁止某些“跨域”請求,特別是 Ajax 請求。
這裡問題在於,預設情況下,執行在瀏覽器應用的 JavaScript 程式碼只能與相同源的伺服器通訊。
因為伺服器位於本地主機埠3001,前端位於本地主機埠3000,所以它們不具有相同的源。
同源策略和 CORS 並不是特定於 React 或 Node 的,它實際上是 web 應用操作的通用原則。
我們可以通過使用 Node 的 cors 中介軟體來允許來自其他源的請求。
安裝cors
npm install cors
使用中介軟體並允許來自所有來源的請求:
const cors = require('cors')
app.use(cors())
現在前端工作正常了!但是,在後端還沒有實現更改便箋重要性的功能。
Application to the Internet
【將應用部署到網上】
現在整個棧已經準備就緒,現在將應用遷移到網際網路上。 我們將使用古老的 Heroku https://www.Heroku.com 。
如果您以前從未使用過 Heroku,您可以從Heroku 文件或通過谷歌搜尋找到指令。
向專案的根目錄新增一個名為 Procfile的檔案,告訴 Heroku 如何啟動應用。
web: npm start
更改應用在index.js 檔案底部使用的埠定義,如下所示:
const PORT = process.env.PORT || 3001app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`)
})
現在我們使用定義在環境變數的埠,如果環境變數 PORT 是未定義的,則使用埠3001。
Heroku 會在環境變數的基礎上配置應用埠。
在專案目錄中建立一個 Git 倉庫,並使用如下內容新增 .gitignore
node_modules
使用命令heroku create建立一個 Heroku 應用,將你的程式碼提交到倉庫並將其推送到Heroku,git push Heroku main。
如果一切順利,應用就能正常工作:
如果沒有執行成功,可以通過使用命令heroku logs 讀取 heroku logs 來發現問題。
前端也與 Heroku 的後端一起工作。 可以將前端的後端地址更改為後端在 Heroku 的地址http://localhost:3001。
Frontend production build
【前端生產構建】
到目前為止,我們一直在開發模式 中執行 React code。
開發模式下,應用提供清晰的錯誤訊息,立即向瀏覽器渲染程式碼更改,等等。
部署應用時,需要建立一個生產構建或一個為生產而優化的應用版本。
使用create-react-app 建立的應用的生產構建可以使用命令npm run build建立。
從前端專案的根目錄執行這個命令,將建立一個名為build 的目錄(其中包含應用中唯一的 HTML 檔案index. HTML) ,其中包含目錄static。
應用的 JavaScript 程式碼的Minified版本將生成到static 目錄。 即使應用程式碼位於多個檔案中,所有的 JavaScript 都將被縮小到一個檔案中。 應用依賴項的所有程式碼也將縮小到這個單一檔案中。
縮小後的程式碼可讀性不是很好,開頭是這樣的:
!function(e){function r(r){for(var n,f,i=r[0],l=r[1],a=r[2],c=0,s=[];c<i.length;c++)f=i[c],o[f]&&s.push(o[f][0]),o[f]=0;for(n in l)Object.prototype.hasOwnProperty.call(l,n)&&(e[n]=l[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,a||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var l=t[i];0!==o[l]&&(n=!1)}n&&(u.splice(r--,1),e=f(f.s=t[0]))}return e}var n={},o={2:0},u=[];function f(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.m=e,f.c=n,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})
Serving static files from the backend
【從後端服務部署靜態檔案】
部署前端可以將生產構建( build 目錄)複製到後端倉庫的根目錄,並配置後端以顯示前端的 main page (檔案 build/index.html)作為其主頁。
我們從將前端的生產構建複製到後端的根目錄。 使用一臺Mac 或 Linux 計算機,可以通過命令從前端目錄進行復制
cp -r build ../../../osa3/notes-backend
如果你使用的Windows作業系統,你可以使用copy 或者 xcopy 命令。要麼就簡單地使用複製貼上即可。
後端目錄現在應該如下所示:
為了讓 express 顯示 static content、 頁面 index.html 和它用來fetch的 JavaScript 等等,我們需要一個來自 express 的內建中介軟體,稱為static。
在中介軟體宣告中新增如下內容時
app.use(express.static('build'))
每當 express 收到一個 HTTP GET 請求時,它都會首先檢查build 目錄是否包含與請求地址對應的檔案。 如果找到正確的檔案,express 將返回該檔案。
現在 HTTP GET 向地址www.serversaddress.com/index.html或 www.serversaddress.com 的GET請求,將顯示 React 前端。 Get 請求到地址 www.serversaddress.com/notes 將由後端程式碼處理。
因為現在的情況下,前端和後端都在同一個地址,所以可以宣告 baseUrl 為relative URL,省略宣告伺服器的部分。
import axios from 'axios'
const baseUrl = '/api/notes'
const getAll = () => {
const request = axios.get(baseUrl)
return request.then(response => response.data)
}
// ...
更改之後,我們必須建立一個新的生產構建,並將其複製到後端儲存庫的根。
該應用現在可以從後端 地址 http://localhost:3001 中使用:
我們的應用現在的工作方式與我們在第0章節中研究的單頁應用 示例應用完全一樣。
當我們使用瀏覽器訪問地址 http://localhost:3001 時,伺服器從build 倉庫返回index. html 檔案。 檔案的摘要內容如下:
<head>
<meta charset="utf-8"/>
<title>React App</title>
<link href="/static/css/main.f9a47af2.chunk.css" rel="stylesheet">
</head>
<body>
<div id="root"></div>
<script src="/static/js/1.578f4ea1.chunk.js"></script>
<script src="/static/js/main.104ca08d.chunk.js"></script>
</body>
</html>
該檔案包含一些指令,用於獲取定義應用樣式的 CSS 樣式表,以及兩個script 標籤,這些標記說明瀏覽器獲取應用的 JavaScript 程式碼——即實際的 React 應用。
React程式碼從伺服器地址 http://localhost:3001/api/notes 獲取便箋,並將它們渲染到螢幕上。 伺服器和瀏覽器之間的通訊可以在開發控制檯的Network 選項卡中看到:
確保應用的生產版本在本地正常工作之後,將前端的生產構建提交到後端儲存庫,並將程式碼再次推送到 Heroku。
現在還沒有新增改變後端便箋重要性的功能。
應用現在將便箋儲存到一個變數中。 如果應用崩潰或重新啟動,所有資料都將消失。
因此應用需要一個資料庫。
Streamlining deploying of the frontend
【流程化前端部署】
為了簡化建立前端的新的生產構建,我們在後端儲存庫的package.json 中新增一些 npm-scripts:
{
"scripts": {
//...
"build:ui": "rm -rf build && cd ../../osa2/materiaali/notes-new && npm run build --prod && cp -r build ../../../osa3/notes-backend/",
"deploy": "git push heroku main",
"deploy:full": "npm run build:ui && git add . && git commit -m uibuild && npm run deploy",
"logs:prod": "heroku logs --tail"
}
}
指令碼 npm run build:ui用於構建前端,並在後端儲存庫下複製生產版本。npm run deploy 會將當前的後端版本釋出到heroku.
npm run deploy:full 會將這兩者結合起來,幷包含更新後端儲存庫所需的git 命令。
還有一個指令碼 npm run logs:prod 用於顯示 heroku 日誌。
我構建的指令碼中的目錄路徑 build:ui 依賴於檔案系統中儲存庫的位置。
在Windows中,npm 指令碼預設是執行在cmd.exe 這個預設的shell中的,而它並不支援bash命令。因此如果希望以上的bash命令運轉良好,可以將預設的shell換成bash(預設Windows安裝Git時已經安裝了Bash):
Proxy
【代理】
前端上的更改導致它不能再在開發模式下工作(當使用命令 npm start 啟動時) ,因為到後端的連線無法工作。
這是由於將後端地址更改為了一個相對 URL:
const baseUrl = '/api/notes'
因為在開發模式下,前端位於地址localhost: 3000,所以對後端的請求會傳送到錯誤的地址localhost:3000/api/notes。 而後端位於localhost: 3001。
如果這個專案是用 create-react-app 建立的,將如下宣告新增到前端倉庫的package.json 檔案中就足夠了。
{
"dependencies": {
// ...
},
"scripts": {
// ...
},
"proxy": "http://localhost:3001"}
在重新啟動之後,React 開發環境將作為一個代理工作。 如果 React 程式碼對伺服器地址http://localhost:3000發出了一個 HTTP 請求,而不是 React 應用本身管理的地址(即當請求不是為了獲取應用的 CSS 或 JavaScript) ,那麼該請求將被重定向到 HTTP://localhost:3001 的伺服器。
現在前端可以在開發和生產模式下與伺服器一起工作。
現在的方法部署新版本需要生成新的前端生產構建並將其複製到後端儲存庫。 這使得建立一個自動化的部署管道變得更加困難。 部署管道是指通過不同的測試和質量檢查將程式碼從開發人員的計算機轉移到生產環境的自動化控制的方法。有多種方法可以實現這一點(例如將後端和前端程式碼放到同一倉庫中) 。
相關文章
- Web全棧開發學習筆記—Part3 用NodeJS和Express寫服務端程式—a.Node.js 與 ExpressWeb全棧筆記NodeJSExpress服務端Node.js
- 用“MEAN”技術棧開發web應用(二)express搭建服務端框架WebExpress服務端框架
- Web全棧開發學習筆記—Part2 與服務端通訊—e.給React應用加點樣式Web全棧筆記服務端React
- 從零到部署:用 Vue 和 Express 實現迷你全棧電商應用(七)VueExpress全棧
- 從零到部署:用 Vue 和 Express 實現迷你全棧電商應用(五)VueExpress全棧
- 從零到部署:用 Vue 和 Express 實現迷你全棧電商應用(一)VueExpress全棧
- 從零到部署:用 Vue 和 Express 實現迷你全棧電商應用(三)VueExpress全棧
- 從零到部署:用 Vue 和 Express 實現迷你全棧電商應用(四)VueExpress全棧
- Web 開發學習筆記——關於網際網路和網際網路應用Web筆記
- 用 React.js+Egg.js 造輪子 全棧開發旅遊電商應用學習筆記和心得ReactJS全棧筆記
- 使用nodejs和express搭建http web服務NodeJSExpressHTTPWeb
- 華為帳號服務學習筆記(四):Authorization Code模式服務端開發筆記模式服務端
- 《Flask Web開發:基於Python的Web應用開發實戰》學習筆記(二)FlaskWebPython筆記
- web應用服務端cache策略初探Web服務端
- CIFS服務端開發筆記服務端筆記
- 學用Java Web Start 部署應用程式 (轉)JavaWeb
- java web開發--Servlet學習之HelloWorld 從部署到開發全過程JavaWebServlet
- Kinect開發學習筆記之(一)Kinect介紹和應用筆記
- 今日學習筆記:hash 以及 nodejs基本服務筆記NodeJS
- 最簡單的nginx教程 - 如何把一個web應用部署到nginx上NginxWeb
- Flutter 全棧開發體驗——爬蟲與服務端Flutter全棧爬蟲服務端
- web學習:服務端開發的業務需求-路由解析Web服務端路由
- 深度學習 | 如何開發、部署 Serverless 應用?深度學習Server
- 基於JavaScript的現代Web應用全棧開發:MEANJavaScriptWeb全棧
- 小白的學習筆記——服務拆分和遠端呼叫筆記
- 自開發Web應用和SAPCustomerDataCloudIdentity服務的整合WebCloudIDE
- Web 開發學習筆記(3) — 申請和部署HTTPS證書Web筆記HTTP
- PHP - 《高效能php應用開發》學習筆記PHP筆記
- Go基礎學習記錄 – 編寫Web應用程 – Web開發輸入驗證(三)GoWeb
- [譯] 如何編寫全棧 JavaScript 應用全棧JavaScript
- 用 Ansible 部署無服務應用!
- 《白帽子講WEB安全》學習筆記之第13章應用層拒絕服務攻擊Web筆記
- MERN全棧開發 使用Mongo Express React和Node全棧GoExpressReact
- this和super的區別和應用 學習筆記筆記
- 全棧網頁開發學習筆記—Part1 React入門—a.React簡介全棧網頁筆記React
- 【譯】使用 MongoDB,React,Node 和 Express(MERN)構建一個全棧應用MongoDBReactExpress全棧
- 用Apache服務部署網站Apache網站
- 用nodejs-websocket開發一個websoket服務NodeJSWeb