背景
- A 專案和 B 專案均是 Laravel + dingo/api 構建的專案
- A 專案通過 API_DOMAIN 配置了 API 介面的域名,B 專案沒有
- 本地開發時兩個專案在同一環境下,通過域名區分虛擬主機,域名用 hosts 指向 127.0.0.1
正文
由於某個原因,A 專案需要呼叫到 B 專案的某個介面,於是我使用 guzzle 去呼叫 B 專案的介面。
但是!!guzzle 卻一直返回 404 響應!
通過本地使用 Postman 呼叫介面,我可以肯定 B 專案的該介面是肯定存在並且可以正常使用的。
這就非常奇怪了,為什麼偏偏使用 guzzle 呼叫就會返回 404 響應?沒有辦法,只能根據 debug 資訊裡的 trace 一步步追查下去了。
追查過程非常曲折,就不在此贅述了,最終除錯發現原因是路由的 host 驗證沒通過(\Illuminate\Routing\Matching\HostValidator
)。Request
物件裡的 host 是 B 專案的域名,但是HostValidator
裡的 host 卻要求是 A 專案的 API_DOMAIN 域名,這就非常詭異了,初步懷疑是不是 Laravel 專案讀取 .env 檔案時會把裡面的值都設定到環境變數裡。
驗證猜想,為了不讀取 .env 檔案,在 B 專案快取配置:
$ php artisan config:cache
再次在 A 專案裡使用 guzzle 呼叫 B 專案介面,介面返回成功!真是絕了,這特麼都行,這 .env 檔案載入看樣子有坑啊。
可是本地除錯終不能一直快取配置啊,嘗試尋找其他解決方案。
先清除 B 專案配置快取,並使用 API_DOMAIN 配置 API 介面的域名,Postman 直接呼叫 B 專案介面,返回正常。
在 A 專案裡使用 guzzle 呼叫 B 專案介面(對應修改了 url ),這次更牛逼了,返回雖然也是 404 響應,但不是 dingo/api 的 json 返回值,而是 Laravel 的 web 路由返回的 404 頁面!這次直接進入不了 B 專案的 dingo/api 路由。。。在 B 專案快取配置,guzzle 請求響應正常。
越來越有意思了,繼續嘗試,清除所有快取,把 A 、B 專案都配置成 API_PREFIX 模式,Postman 直接呼叫 B 專案介面,返回正常,在 A 專案裡使用 guzzle 呼叫 B 專案介面果然也返回正常,看樣子真的是 .env 檔案載入有坑啊。
衍生
想到 .env 檔案載入有坑,突然就是一激靈,這不就意味著其實不僅僅是 API_DOMAIN 的值會有問題,所有 .env 檔案裡配置的變數其實全都會有問題!!比如資料庫 DB_DATABASE !!哇,賊恐怖,立馬寫測試介面進行嘗試,B 專案介面直接返回config('database.connections.mysql')
的值。
果然,在 A 專案裡使用 guzzle 呼叫 B 專案介面時,B 專案介面裡config('database.connections.mysql')
返回的是 A 專案的資料庫配置。。。。在 B 專案快取了配置之後,返回的就是正常的 B 專案資料庫配置了。
哇,賊恐怖,簡直無解了啊,這是逼我本地開發也要快取 B 專案的配置了。
結論
折騰了這麼久,最終只能妥協,快取 B 專案的配置進行開發,希望過後我還會記得我在本地快取過 B 專案的配置。。。
還有,線上環境也要注意部署在一臺主機上的 Laravel 專案一定要快取配置!!不然搞不好要出人命的 T_T