獲取登錄驗證碼失敗及前后端不同域導致session丟失問題分析記錄


前言

前兩周在把兄弟公司的幾個服務部署到我們公司測試環境服務器的時候又遇到了不少問題,因為是前后端分離的項目,所以這次也同樣遇到了跨域問題,解決方式也跟上一回的不一樣,這里就再來分析記錄一下。

登錄驗證碼在本地獲取正常但部署到服務器報空指針異常問題

問題描述:

登錄頁面的驗證碼,在本地運行項目的時候可以正常獲取和顯示,但部署到測試環境服務器上驗證碼圖片卻無法顯示出來,如下圖所示:
追了一下后端服務器日志,發現后端報空指針異常,報錯信息如下所示:
java.lang.NullPointerException: null
at sun.awt.FontConfiguration.getVersion(FontConfiguration.java:1264)
at sun.awt.FontConfiguration.readFontConfigFile(FontConfiguration.java:219)
at sun.awt.FontConfiguration.init(FontConfiguration.java:107)
at sun.awt.X11FontManager.createFontConfiguration(X11FontManager.java:774)
at sun.font.SunFontManager$2.run(SunFontManager.java:431)
at java.security.AccessController.doPrivileged(Native Method)
at sun.font.SunFontManager.(SunFontManager.java:376)
at sun.awt.FcFontManager.(FcFontManager.java:35)
at sun.awt.X11FontManager.(X11FontManager.java:57)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.lang.Class.newInstance(Class.java:442)
at sun.font.FontManagerFactory$1.run(FontManagerFactory.java:83)
at java.security.AccessController.doPrivileged(Native Method)
at sun.font.FontManagerFactory.getInstance(FontManagerFactory.java:74)
at java.awt.Font.getFont2D(Font.java:491)
at java.awt.Font.access$000(Font.java:224)
at java.awt.Font$FontAccessImpl.getFont2D(Font.java:228)
at sun.font.FontUtilities.getFont2D(FontUtilities.java:180)
at sun.java2d.SunGraphics2D.checkFontInfo(SunGraphics2D.java:669)
at sun.java2d.SunGraphics2D.getFontInfo(SunGraphics2D.java:830)
at sun.java2d.pipe.GlyphListPipe.drawString(GlyphListPipe.java:50)
at sun.java2d.SunGraphics2D.drawString(SunGraphics2D.java:2928)
at com.lanmei.common.ImageUtil.createimage(ImageUtil.java:77)
......
跟蹤代碼后發現,在繪制驗證碼圖片時使用了Graphics畫布,Graphics在繪制驗證碼字符時,需要先設定字體,如下所示:
g.setFont(new Font("DejaVu Sans", Font.CENTER_BASELINE, 18));
這就是問題點所在,在windows系統上,運行這行代碼是完全沒問題的,因為windows系統自帶這種字體,可是我們測試環境服務器上運行的linux鏡像系統並沒有這種字體,所以就報空指針異常了。

解決辦法:構建一個帶有指定字體的基礎鏡像

構建了一個自帶“DejaVu Sans”字體的openjdk鏡像,使用該鏡像來運行我們的程序,就能正常獲取和顯示登錄驗證碼了,如下圖所示:
注意:關於構建這個鏡像,有兩種方式可以選擇,一種是創建一個跟原來一樣沒有“DejaVu Sans”字體的基礎openjdk鏡像,然后再執行添加相應字體的命令,對應的Dockerfile編寫方式如下:
FROM openjdk:8-jdk-alpine
ARG JAR_FILE
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
COPY ${JAR_FILE} app.jar
RUN apk add --update ttf-dejavu fontconfig
EXPOSE 8086
ENTRYPOINT ["java","-jar","/app.jar"]
使用這種方式的缺點在於每次構建鏡像的時候都要花很多時間去下載我們所需要的字體,效率很低。
另一種方式則是先在我們自己公司用於存放鏡像的服務器上專門構建一個帶有“DejaVu Sans”字體的openjdk鏡像,然后用它來運行我們的項目,這樣一來能夠滿足功能需求,二來是直接從我們自己的鏡像服務器上拉取鏡像、速度也會快很多。

前后端不同域導致session丟失問題

問題描述:

輸入的登錄驗證碼沒有錯,可是卻一直報:驗證碼錯誤,登錄失敗!
在后端打了一些日志后,發現如下信息:
這里我們登錄驗證碼的完整校驗邏輯是這樣的:用戶請求登錄頁面時,調用后端生成驗證碼的接口,后端生成一個驗證碼返回給前端並將驗證碼字符串緩存在瀏覽器session中,用戶輸入登錄信息后,后端根據用戶輸入的驗證碼與用戶緩存在瀏覽器session中的驗證碼字符串進行比對,若一致則校驗通過,否則校驗失敗。
根據日志可以判斷,這里session中緩存的驗證碼丟失了,導致后端獲取不到。
按F12鍵使用開發者工具查看獲取驗證碼的請求響應,可以看到如下信息:
根據上圖可以得知,后端嘗試將驗證碼緩存到瀏覽器session中時,由於前后端不同域導致該操作被攔截了。

解決辦法:通過前端nginx設置同域代理轉發請求

在nginx配置文件中添加如下配置:
location /hello-sso-service {
    proxy_pass http://xxx.xxx.xxx.xxx:8080/hello-sso-service;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
將與hello-sso-service相關的接口請求代理轉發到對應的后端服務接口,這樣緩存驗證碼到session的操作就不會被攔截了。
更新代碼配置后,重新進行登錄,后端服務就能從session中獲取到相應的驗證碼了,如下圖所示:
 
關於前后端不同域,這次我其實還遇到了另外一個小問題:在退出登錄時,需要跳轉到前端登錄頁面並且在url中攜帶一些參數請求后端一個接口,也就是說,跳轉的地址組成結構為“前端ip:端口+對應的后端接口”。
針對這個問題,我也是使用nginx進行了如下代理:
location /v1 {
    proxy_pass http://xxx.xxx.xxx.xxx:8081/v1;
    proxy_set_header  Host $http_host;
    proxy_set_header  X-Real-IP  $remote_addr;
    proxy_set_header  X-Forwarded-For  $proxy_add_x_forwarded_for;
}

總結

這段時間在部署這些新服務的過程中,學習了不少前后端服務部署的知識,尤其對於前后端跨域問題有了很深刻的體會。所謂“同域”,就是“協議+主機+端口”都相同,反之則稱之為“跨域”。

解決“跨域”問題較常見的辦法就是使用nginx進行反向代理設置,如上文中提到的兩個例子,通過代理使前后端“同域”,就可以解決相應的session設置失敗及接口請求不通等問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM