前后端分離這個問題其實松哥和大家聊過很多了,上周松哥把自己的兩個開源項目部署在服務器上以幫助大家可以快速在線預覽(喜大普奔,兩個開源的 Spring Boot + Vue 前后端分離項目可以在線體驗了),然后群里就有小伙伴想讓松哥來聊聊如何結合 Nginx 來部署前后端分離項目?今天我們就來聊一聊這個話題。
不得不說的跨域
很多人對前后端分離部署感到困惑,其實主要是困惑跨域問題怎么解決。因為前后端分離項目在開發的時候,前端通過 nodejs 來運行,需要一個單獨的端口,后端通過 Tomcat 或者 Jetty 來運行,也需要端口,兩個不同的端口,就造成了跨域。
但是松哥之前多次和大家聊過這個問題,這種跨域並不是我們傳統開發中真正的跨域,這個所謂的跨域只在開發環境中存在,生產環境下就不存在這個跨域問題了。所以我們不能按照以往的通過 JSONP 或者 CORS 之類的手段來解決這個跨域問題。
前后端分離開發中,前端為了能夠模擬出測試數據,並且模擬出請求,一般需要借助於 nodejs 來運行,這是開發時候的狀態,開發時候的配置大家可以參考這篇文章:
等開發完成后,我們會對前端項目編譯打包,編譯打包完成之后,就只剩下一堆 js、css 以及 html 文件了,我們把這些編譯打包后的文件拷貝到后端項目中,這樣再去運行就不存在跨域問題了(例如將編譯打包后的靜態文件拷貝到 Spring Boot 項目的 src/main/resources/static
目錄下)。這種方式我就不再多說了,相信大家都會,今天咱們主要來看看如何結合 Nginx 來部署。
Nginx 大殺器
結合 Nginx 來部署前后端分離項目算是目前的主流方案。一來部署方便,二來通過動靜分離也可以有效提高項目的運行效率。
大家知道我們項目中的資源包含動態資源和靜態資源兩種,其中:
- 動態資源就是那些需要經過容器處理的資源,例如 jsp、freemarker、各種接口等。
- 靜態資源則是那些不需要經過容器處理,收到客戶端請求就可以直接返回的資源,像 js、css、html 以及各種格式的圖片,都屬於靜態資源。
將動靜資源分開部署,可以有效提高靜態資源的加載速度以及整個系統的運行效率。
在前后端分離項目部署中,我們用 Nginx 來做一個反向代理服務器,它既可以代理動態請求,也可以直接提供靜態資源訪問。我們來一起看下。建議大家先閱讀松哥以前關於 Nginx 的一篇舊文,可以有效幫助大家理解后面的配置:
后端部署
后端接口的部署,主要看項目的形式,如果就是普通的 SSM 項目,那就提前准備好 Tomcat ,在 Tomcat 中部署項目,如果是 Spring Boot 項目,可以通過命令直接啟動 jar,如果是微服務項目,存在多個 jar 的話,可以結合 Docker 來部署(參考一鍵部署 Spring Boot 到遠程 Docker 容器),無論是那種形式,對於我們 Java 工程師來說,這都不是問題,我相信這一步大家都能搞定。
后端項目可以在一個非 80 端口上部署,部署成功之后,因為這個后端項目只是提供接口,所以我們並不會直接去訪問他。而是通過 Nginx 請求轉發來訪問這個后端接口。
松哥這里以我去年為一個律所的小程序為例,后端是一個 Spring Boot 工程,那么我可以通過 Docker 部署,也可以直接通過命令來啟動,這里簡單點,直接通過命令來啟動 jar ,如下:
nohup java -jar jinlu.jar > vhr.log &
后端啟動成功之后,我並不急着直接去訪問后端,而是安裝並且去配置一個 Nginx,通過 Nginx 來轉發請求,Nginx 的基本介紹與安裝,大家可以參考(Nginx 極簡入門教程!),我這里就直接來說相關的配置了。
這里我們在 nginx.conf 中做出如下配置:
首先配置上游服務器:
upstream zqq.com{
server 127.0.0.1:9999 weight=2;
}
在這里主要是配置服務端的地址,如果服務端是集群化部署,那么這里就會有多個服務端地址,然后可以通過權重或者 ip hash 等方式進行請求分發。
然后我們在 server 中配置轉發規則:
location /jinlu/ {
proxy_pass http://zqq.com;
tcp_nodelay on;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
這樣配置完成后,假設我目前的域名是 javaboy.org,那么用戶通過 http://www.javaboy.org/jinlu/**
格式的地址就可以訪問到我服務端的接口。
前端部署
以 Vue 為例,如果是 SPA 應用,項目打包之后,就是一個 index.html 還有幾個 js、css、images 以及 fonts ,這些都是靜態文件,我們將靜態文件首先上傳到服務器,然后在 nginx.conf 中配置靜態資源訪問,具體配置如下:
location ~ .*\.(js|css|ico|png|jpg|eot|svg|ttf|woff|html|txt|pdf|) {
root /usr/local/nginx/html/;#所有靜態文件直接讀取硬盤
expires 30d; #緩存30天
}
當然我這里是按照資源類型來攔截的,即后綴為 js、css、ico 等的文件,統統都不進行請求分發,直接從本地的 /usr/local/nginx/html/ 目錄下讀取並返回到前端(我們需要將靜態資源文件上傳到 /usr/local/nginx/html/
目錄下)。
如果我們的服務器上部署了多個項目,這種寫法就不太合適,因為多個項目的前端靜態文件肯定要分門別類,各自放好的,這個時候我們一樣可以通過路徑來攔截,配置如下:
location /jinlu-admin/ {
root /usr/local/nginx/html/jinlu-admin/;#所有靜態文件直接讀取硬盤
expires 30d; #緩存30天
}
這樣,請求路徑是 /jinlu-admin/ 格式的請求,則不會進行請求分發,而是直接從本機的 /usr/local/nginx/html/jinlu-admin/
目錄下返回相關資源。采用這方方式配置靜態資源,我們就可以部署多個項目了,多個項目的部署方式和上面的一樣。
這樣部署完成之后,假設我的域名是 javaboy.org ,那么用戶通過 http://www.javaboy.org/jinlu-admin/**
格式的請求就可以訪問到前端資源了。
此時大家發現,前端的靜態資源和后端的接口現在處於同一個域之中了,這樣就不存在跨域問題,所以我一開始基說不必用 JSONP 或者 CORS 去解決跨域。特殊情況可能需要在 nginx 中配置跨域,這個松哥以后再和大家細聊~
好了,不知道小伙伴有沒有看懂呢?有問題歡迎留言討論。
關注公眾號【江南一點雨】,專注於 Spring Boot+微服務以及前后端分離等全棧技術,定期視頻教程分享,關注后回復 Java ,領取松哥為你精心准備的 Java 干貨!