Spring Boot 的 RestTemplate 遇到「URI is not absolute

Jeff Hsieh
3 min readMay 24, 2019

記錄一下踩到的小坑~

因為後端架構上資料分離的關係,API Server 所需要的資料有一部份會是從另一台 Web Service 來的,因此會需要在程式內部呼叫其他 API,而在呼叫 API 時我們使用的便是 Spring 的 RestTemplate 物件。

會選擇 RestTemplate 物件的原因主要是因為方便,由於我們的 API 都有定義好一個固定的 return 格式,因此所有的 API 都可以用一個通用的 VO 來裝載資料。
使用 RestTemplate 我們就可以把通用 VO 帶入,便可直接得到 parse 完的 VO而不用拿到資料後再自行做序列化。

這次遇到的問題是在呼叫 API 時會遇到下列的 Exception:java.lang.IllegalArgumentException: URI is not absolute

從錯誤訊息可以知道是 URL 的格式錯誤,但複雜的地方在於,我們的 URL 是設定在環境變數中,再由 devops 將環境變數載入到 properties 檔案內,程式碼再透過 env 的方式將 URL 載進來給 RestTemplate

而 devops 在設定環境變數時是設定「anotherServer」這種格式,我們的 GCP 在傳送 request 時會自動將「anotherServer」轉換成 ip,也就可以把 request 送到相對應的 container 內

那為什麼 RestTemplate 會跳 exception 呢?在 trace 完 RestTemplate 的原始碼後會發現, RestTemplate 在執行 execute 發送 request 時會建立 ClientHttpRequest ,這時會用到 java.net 的 URL 物件來把 URI 建立成 URL

而重點就在於這個 URL 物件,會透過 uri.isAbsolute() 來檢查 URI 的合法性,一個合法的 URI 前面會帶開頭,例如http、file…等等,而我們的「anotherServer」前面沒有這樣的開頭,也因此就會被判斷為不合法的 URI 而跳 exception 了

解決方式很簡單,請 devops 將「anotherServer」前面加上開頭變成「http://anotherServer」,如此就能通過 URI 的檢查,也可以讓 GCP 後續自行轉換成內部 container 的 ip 去發送 request,而不用寫死網址造成 GCP 會先繞到外網再繞進來,造成不必要的負擔了~

小結:RestTemplate 所接收的 URL 必須要是合法的格式,然而不一定要是完整的網址或 ip ,只要開頭能通過檢查,也可以用 devops 習慣的 container name 去處理喔!

--

--

Jeff Hsieh

資深後端工程師,熟悉JAVA與現代網頁後端技術與框架,並具備金融市場交易知識