前言
最近遇到一個需求:用postMessage
來實現跨域通訊。
其中有一個注意的地方:即接收方來收到訊息時需要對傳送方的 origin
進行檢查,如果不是目標傳送方,則什麼都不做,這是出於安全考慮推薦的方式。
我手中有的資料有:訊息事件中的 event.origin(即當前傳送方的源)、目標傳送方的url字串。所以為了進行安全檢查,我得先從目標傳送方的url字串中提取出 origin
資訊。
那麼問題來了,怎麼提取呢?
——當然用正規表示式最簡單!
origin是什麼
在介紹提取的正規表示式之前,我們得先搞清楚我們要提取的是url字串中的哪一部分的字元。我們知道要提取的是origin
資訊,那origin
是什麼意思呢?
前端開發經常聽到一個詞“同源策略”,origin
即為其中的“源”。一個 URL 具體由哪幾部分組成,可以參考這篇文章。
而 origin = scheme(協議)+ domain(域名)+port(埠)
例如:
url= “http://baidu.com:8080/pub/new”;
origin = “http://baidu.com:8080”;
匹配正規表示式
我想用 RegExp.exec()方法來提取 origin。構造一個RegExp物件有兩種方法:
-
RegExp(pattern [, flags]), 如 new RegExp(“ab+c”, “i”);
-
/pattern/flags, 如 /ab+c/i;
注意:很多人誤認為這2種方法的區別只在於前者 pattern 是一個字串,我原本也是這麼認為的。結果就被這個潛意識坑得很慘。
匹配 origin 的正則 pattern 如下所示,能匹配http/https協議、域名中帶“-”、“_”字元如“dx-meituan.dxw_mei.com”。至於具體如何匹配到每一個字元的,請自行參考RegExp物件。
^https?://[w-.]+(:d+)?
下面將分別用前面介紹的2種方法建立 RegExp 物件,看看會遇到什麼坑兒。
-
RegExp(pattern [, flags])
TEST 0:
var url = "https://dx.sansan.com:8080/test/index";
var origin = new RegExp("^https?://[w-.]+(:d+)?","i").exec(url)[0];
結果:null, 即沒有找到任何匹配結果
怎麼會這樣??!!沒有問題呀,我重新檢查了每一個字元具體匹配過程,確實沒問題呀。。。。
TEST 1:
var url = "https://dx.sansan.com:8080/test/index";
var origin = new RegExp("^https?://[\w-.]+(:\d+)?",i).exec(url)[0];
結果:https://dx.sansan.com:8080
居然匹配成功了!!!這是個什麼鬼?
原來是因為使用new RegExp(pattern [, flags])去建立一個正則物件,pattern 是一個 string 型別,所以 pattern 裡面的所有字元都是要匹配的真實字元。如 pattern = “w”,就是從“world”中匹配“w”這個字母,而不是匹配 0-9或 A-Z 或 a-z 中的一個字元。所以要想達到後一種效果,就得寫成pattern = “\w”。這也解釋了匹配”.”這個字元時,不用寫成“.”(因為.是正則中的特殊字元,要想匹配”.”字元一般要寫成”.”)。
我實驗後的結論是:使用new RegExp(pattern [, flags]),pattern中字元就是要匹配的字元,其中單一的“”會被忽略,如”w”==”w”; 要想使用正則中的包含“”的特殊符號(如w和d),得寫成”\w”和”\d”。
-
/pattern/flags
TEST 0:
var url = "https://dx.sansan.com:8080/test/index";
var origin = /^https?://[w-.]+(:d+)?/i.exec(url)[0];
結果:報錯 unexpected SyntexError !!
語法錯誤,這個比較容易排查。發現是”?://”中的”/”與 /pattern/flags 中的”/”衝突了,在這種方式下,”/”字元變成了一個特殊字元。
TEST 1:
var url = "https://dx.sansan.com:8080/test/index";
var origin = /^https?://[w-.]+(:d+)?/i.exec(url)[0];
結果:https://dx.sansan.com:8080
匹配成功了!
所以這種方式匹配時,正則中的特殊符號如w和d是生效的,但要想匹配”//”,得寫成”//”。
結語
所以以前自己的潛意識認知就存在錯誤。
下面兩種方式匹配字串時,pattern 除了是否是字串型別,寫法上有些字元也是不同的。
-
RegExp(pattern [, flags]), 如 new RegExp(“ab+c”, “i”);
-
/pattern/flags, 如 /ab+c/i;