多端混合開發時跨域問題的處理

仙人掌發表於2021-02-26

相信“跨域資源共享”(Cross-origin resource sharing)對於論壇內的大部分人來說,已經是老生常談了,所以就不再贅述關於CORS的定義、各種解決方案等等,不過可以推薦阮大神的一篇相關博文,希望從頭瞭解CORS的可以參考。這裡主要寫下關於混合開發時針對各個端(web、Android、iOS、微信小程式)的跨域問題的處理。
如果你是一個對站點安全比較佛系,追求可用性的人,那直接

header('Access-Control-Allow-Origin:*');

就可以把“跨域”二字拋之腦後,大門敞開,來者不拒,也就不會擔心自己人因跨域被攔截了。當然,對於公開運營的站點,最好別這麼做。
若是希望自己的家不被陌生人隨意進入,導致家裡出現“意外”,那這個 Access-Control-Allow-Origin就需要按需設定了。
由於我們需要設定讓指定的域名允許跨域訪問,那麼就設定一個白名單$allowedOrigins,每次判斷來訪的域名是否在白名單中,是的話就設定介面響應的header中Access-Control-Allow-Origin的值為該域名。具體程式碼可以參考下面。

const ALLOW_ORIGINS = [
    'https://foo.com',
    'https://bar.com'
];
private function checkOrigin()
{
    if (isset($_SERVER["HTTP_ORIGIN"])) {
        $httpOrigin = $_SERVER["HTTP_ORIGIN"];
        in_array($httpOrigin, self::ALLOW_ORIGINS) && header('Access-Control-Allow-Origin:' . $httpOrigin);
    }
}

以上程式碼已經可以解決web端的跨域問題,但是因為跨域本身就是客戶端瀏覽器的控制,如果是混合開發,還需要考慮安卓端跟ios端app的問題。由於我們是採用uniapp進行跨平臺開發,針對安卓端應用,包括微信小程式,目前沒發現跨域問題,但是ios端在配置了上面的程式碼之後,就出現了跨域問題,排查後發現ios端傳送到服務端介面的HTTP_ORIGIN值是字串"null”,查詢之後發現,ios端原生的APP傳送請求時,HTTP_ORIGIN一般為localhost:8000 ,但我們這個是經過封裝的,uniapp使用cordova包進行底層封裝處理,使用這個包時api請求傳送時會帶值為"null”的HTTP_ORIGIN頭。所以為了相容iOS這種情況,要麼就是在ALLOW_ORIGINS中新增一個“null”的域名,要麼就是在下面程式中做特殊判斷。當然因為本身對手機APP原生開發基本不瞭解,所以這塊原理性的知識欠缺,很難去達到完全的“所以然”的程度,如果有APP原生開發的小夥伴對這塊有研究過,十分歡迎指教。
另外補充個“題外話”,上面程式碼中用到了in_array(),如果ALLOW_ORIGINS資料量很大的話,最好能先把ALLOW_ORIGINS改成以域名為鍵,然後隨意定一個值作為鍵的值的鍵值對形式,然後改成用 isset(self::ALLOW_ORIGINS[$httpOrigin])這樣來判斷,因為in_array的時間複雜度為O(n),在n很大的時候,還是有優化空間的。同時isset屬於php的語法結構,像in_array(),array_key_exists()屬於函式,相比之下isset還是效率略高的。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章