無法通過IP地址反查mac地址,這是兩個獨立的協(xié)議層。
創(chuàng)新互聯(lián)是一家專注于網(wǎng)站建設、網(wǎng)站設計與策劃設計,尼金平網(wǎng)站建設哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設十多年,網(wǎng)設計領域的專業(yè)建站公司;建站業(yè)務涵蓋:尼金平等地區(qū)。尼金平做網(wǎng)站價格咨詢:18982081108
你想嘍,IP地址可以綁定到任意的一臺電腦上,就已經(jīng)說明IP跟Mac沒有特別直接的關(guān)系。
前端工程師都知道 JavaScript 有基本的異常處理能力。我們可以 throw new Error(),瀏覽器也會在我們調(diào)用 API 出錯時拋出異常。但估計絕大多數(shù)前端工程師都沒考慮過收集這些異常信息。反正只要 JavaScript 出錯后刷新不復現(xiàn),那用戶就可以通過刷新解決問題,瀏覽器不會崩潰,當沒有發(fā)生過好了。這種假設在 Single Page App 流行之前還是成立的?,F(xiàn)在的 Single Page App 運行一段時間后狀態(tài)復雜無比,用戶可能進行了若干輸入操作才來到這里的,說刷新就刷新???之前的操作豈不要完全重做?所以我們還是有必要捕獲和分析這些異常信息的,然后我們就可以修改代碼避免影響用戶體驗。
捕獲異常的方式
我們自己寫的 throw new Error() 想要捕獲當然可以捕獲,因為我們很清楚 throw 寫在哪里了。但是調(diào)用瀏覽器 API 時發(fā)生的異常就不一定那么容易捕獲了,有些 API 在標準里就寫著會拋出異常,有些 API 只有個別瀏覽器因為實現(xiàn)差異或者有缺陷而拋出異常。對于前者我們還能通過 try-catch 捕獲,對于后者我們必須監(jiān)聽全局的異常然后捕獲。
try-catch
如果有些瀏覽器 API 是已知會拋出異常的,那我們就需要把調(diào)用放到 try-catch 里面,避免因為出錯而導致整個程序進入非法狀態(tài)。例如說 window.localStorage 就是這樣的一個 API,在寫入數(shù)據(jù)超過容量限制后就會拋出異常,在 Safari 的隱私瀏覽模式下也會如此。
try { localStorage.setItem('date', Date.now());} catch (error) { reportError(error);}
另一個常見的 try-catch 適用場景是回調(diào)。因為回調(diào)函數(shù)的代碼是我們不可控的,代碼質(zhì)量如何,會不會調(diào)用其它會拋出異常的 API,我們一概不知道。為了不要因為回調(diào)出錯而導致調(diào)用回調(diào)后的其它代碼無法執(zhí)行,所以把調(diào)用回到放到 try-catch 里面是必須的。
listeners.forEach(function(listener) { try { listener(); } catch (error) { reportError(error); }});
window.onerror
對于 try-catch 覆蓋不到的地方,如果出現(xiàn)異常就只能通過 window.onerror 來捕獲了。
window.onerror = function(errorMessage, scriptURI, lineNumber) { reportError({ message: errorMessage, script: scriptURI, line: lineNumber });}
注意不要耍小聰明使用 window.addEventListener 或 window.attachEvent 的形式去監(jiān)聽 window.onerror。很多瀏覽器只實現(xiàn)了 window.onerror,或者是只有 window.onerror 的實現(xiàn)是標準的??紤]到標準草案定義的也是 window.onerror,我們使用 window.onerror 就好了。
屬性丟失
假設我們有一個 reportError 函數(shù)用來收集捕獲到的異常,然后批量發(fā)送到服務器端存儲以便查詢分析,那么我們會想要收集哪些信息呢?比較有用的信息包括:錯誤類型(name)、錯誤消息(message)、腳本文件地址(script)、行號(line)、列號(column)、堆棧跟蹤(stack)。如果一個異常是通過 try-catch 捕獲到的,這些信息都在 Error 對象上(主流瀏覽器都支持),所以 reportError 也能收集到這些信息。但如果是通過 window.onerror 捕獲到的,我們都知道這個事件函數(shù)只有 3 個參數(shù),所以這 3 個參數(shù)以外的信息就丟失了。
序列化消息
如果 Error 對象是我們自己創(chuàng)建的話,那么 error.message 就是由我們控制的?;旧衔覀儼咽裁捶胚M error.message 里面,window.onerror 的第一個參數(shù)(message)就會是什么。(瀏覽器其實會略作修改,例如加上 'Uncaught Error: ' 前綴。)因此我們可以把我們關(guān)注的屬性序列化(例如 JSON.Stringify)后存放到 error.message 里面,然后在 window.onerror 讀取出來反序列化就可以了。當然,這僅限于我們自己創(chuàng)建的 Error 對象。
第五個參數(shù)
瀏覽器廠商也知道大家在使用 window.onerror 時受到的限制,所以開始往 window.onerror 上面添加新的參數(shù)。考慮到只有行號沒有列號好像不是很對稱的樣子,IE 首先把列號加上了,放在第四個參數(shù)。然而大家更關(guān)心的是能否拿到完整的堆棧,于是 Firefox 說不如把堆棧放在第五個參數(shù)吧。但 Chrome 說那還不如把整個 Error 對象放在第五個參數(shù),大家想讀取什么屬性都可以了,包括自定義屬性。結(jié)果由于 Chrome 動作比較快,在 Chrome 30 實現(xiàn)了新的 window.onerror 簽名,導致標準草案也就跟著這樣寫了。
window.onerror = function( errorMessage, scriptURI, lineNumber, columnNumber, error) { if (error) { reportError(error); } else { reportError({ message: errorMessage, script: scriptURI, line: lineNumber, column: columnNumber }); }}
屬性正規(guī)化
我們之前討論到的 Error 對象屬性,其名稱都是基于 Chrome 命名方式的,然而不同瀏覽器對 Error 對象屬性的命名方式各不相同,例如腳本文件地址在 Chrome 叫做 script 但在 Firefox 叫做 filename。因此,我們還需要一個專門的函數(shù)來對Error 對象進行正規(guī)化處理,也就是把不同的屬性名稱都映射到統(tǒng)一的屬性名稱上。具體做法可以參考這篇文章。盡管瀏覽器實現(xiàn)會更新,但人手維護一份這樣的映射表并不會太難。
類似的是堆棧跟蹤(stack)的格式。這個屬性以純文本的形式保存一份異常在發(fā)生時的堆棧信息,由于各個瀏覽器使用的文本格式不一樣,所以也需要人手維護一份正則表達,用于從純文本中提取每一幀的函數(shù)名(identifier)、文件(script)、行號(line)和列號(column)。
安全限制
如果你也遇到過消息為 'Script error.' 的錯誤,你會明白我在說什么的,這其實是瀏覽器針對不同源(origin)腳本文件的限制。這個安全限制的理由是這樣的:假設一家網(wǎng)銀在用戶登錄后返回的 HTML 跟匿名用戶看到的 HTML 不一樣,一個第三方網(wǎng)站就能把這家網(wǎng)銀的 URI 放到 script.src 屬性里面。HTML 當然不可能被當做 JS 解析啦,所以瀏覽器會拋出異常,而這個第三方網(wǎng)站就能通過解析異常的位置來判斷用戶是否有登錄。為此瀏覽器對于不同源腳本文件拋出的異常一律進行過濾,過濾得只剩下 'Script error.' 這樣一條不變的消息,其它屬性統(tǒng)統(tǒng)消失。
對于有一定規(guī)模的網(wǎng)站來說,腳本文件放在 CDN 上,不同源是很正常的。現(xiàn)在就算是自己做個小網(wǎng)站,常見框架如 jQuery 和 Backbone 都能直接引用公共 CDN 上的版本,加速用戶下載。所以這個安全限制確實造成了一些麻煩,導致我們從 Chrome 和 Firefox 收集到的異常信息都是無用的 'Script error.'。
CORS
想要繞過這個限制,只要保證腳本文件和頁面本身同源即可。但把腳本文件放在不經(jīng) CDN 加速的服務器上,豈不降低用戶下載速度?一個解決方案是,腳本文件繼續(xù)放在 CDN 上,利用 XMLHttpRequest 通過 CORS 把內(nèi)容下載回來,再創(chuàng)建 script 標簽注入到頁面當中。在頁面當中內(nèi)嵌的代碼當然是同源的啦。
這說起來很簡單,但實現(xiàn)起來卻有很多細節(jié)問題。用一個簡單的例子來說:
script src=""/scriptscript (function step2() {})();/scriptscript src=""/script
我們都知道這個 step1、step2、step3 如果存在依賴關(guān)系的話,則必須嚴格按照這個順序執(zhí)行,否則就可能出錯。瀏覽器可以并行請求 step1 和 step3 的文件,但在執(zhí)行時順序是保證的。如果我們自己通過 XMLHttpRequest 獲取 step1 和 step3 的文件內(nèi)容,我們就需要自行保證其順序正確性。此外不要忘記了 step2,在 step1 以非阻塞形式下載的時候 step2 就可以被執(zhí)行了,所以我們還必須人為干預 step2 讓它等待 step1 完成后再執(zhí)行。
如果我們已經(jīng)有一整套工具來生成網(wǎng)站上不同頁面的 script 標簽的話,我們就需要調(diào)整一下這套工具讓它對 script 標簽做出改動:
script scheduleRemoteScript('');/scriptscript scheduleInlineScript(function code() { (function step2() {})(); });/scriptscript scheduleRemoteScript('');/script
我們需要實現(xiàn) scheduleRemoteScript 和 scheduleInlineScript 這兩個函數(shù),并且保證它們在第一個引用外部腳本文件的 script 標簽之前就被定義好,然后余下的 script 標簽都會被改寫成上面這種形式。注意原本立即執(zhí)行的 step2 函數(shù)被放到了一個更大的 code 函數(shù)里面了。code 函數(shù)并不會被執(zhí)行,它只是一個容器而已,這樣使得原本 step2 的代碼不需要轉(zhuǎn)義就能保留下來,但又不會被立即執(zhí)行。
接下來我們還需要實現(xiàn)一套完整的機制,保證這些由 scheduleRemoteScript 根據(jù)地址下載回來的文件內(nèi)容和由 scheduleInlineScript 直接獲取到的代碼能夠按照正確的順序一個接一個地執(zhí)行。詳細的代碼我就不在這里給出了,大家有興趣可以自己去實現(xiàn)。
行號反查
通過 CORS 獲取內(nèi)容再把代碼注入頁面能夠突破安全限制,但會引入一個新的問題,那就是行號沖突。原本通過 error.script 可以定位到唯一的腳本文件,再通過 error.line 可以定位到唯一的行號。現(xiàn)在由于都是頁面內(nèi)嵌的代碼,多個 script 標簽并不能通過 error.script 來區(qū)分,然而每一個 script 標簽內(nèi)部的行號都是從 1 算起的,結(jié)果就導致我們無法利用異常信息定位錯誤所在的源代碼位置。
為了避免行號沖突,我們可以浪費一些行號,使得每一個 script 標簽中有實際代碼所使用的行號區(qū)間互相不重疊。舉個例子來說,假設每個 script 標簽中的實際代碼都不超過 1000 行,那么我可以讓第一個 script 標簽中的代碼占用第 1–1000 行,讓第二個 script 標簽中的代碼占用第 1001–2000 行(前面插入 1000 行空行),第三個 script 標簽種的代碼占用第 2001–3000 行(前面插入 2000 行空行),以此類推。然后我們使用 data-* 屬性記錄這些信息,便于反查。
script data-src="" data-line-start="1" // code for step 1/scriptscript data-line-start="1001" // '\n' * 1000 // code for step 2/scriptscript data-src="" data-line-start="2001" // '\n' * 2000 // code for step 3/script
經(jīng)過這樣處理后,如果一個錯誤的 error.line 是 3005 的話,那意味著實際的 error.script 應該是 '',而實際的 error.line 則應該是 5。我們可以在之前提到的 reportError 函數(shù)里面完成這項行號反查工作。
當然,由于我們沒辦法保證每一個腳本文件只有 1000 行,也有可能有些腳本文件明顯小于 1000 行,所以其實不需要固定分配 1000 行的區(qū)間給每一個 script 標簽。我們可以根據(jù)實際腳本行數(shù)來分配區(qū)間,只要保證每一個 script 標簽所使用的區(qū)間互不重疊就可以了。
crossorigin 屬性
瀏覽器對于不同源的內(nèi)容進行的安全限制當然不僅限于 script 標簽。既然 XMLHttpRequest 可以通過 CORS 來突破這個限制,為什么直接通過標簽引用的資源就不可以呢?這當然是可以的。
針對 script 標簽引用不同源腳本文件的限制同樣作用于 img 標簽引用不同源圖片文件。如果一個 img 標簽是不同源的話,一旦在 canvas 繪圖時用到了,該 canvas 將變?yōu)橹粚憼顟B(tài),保證網(wǎng)站不能通過 JavaScript 竊取未授權(quán)的不同源圖片數(shù)據(jù)。后來 img 標簽通過引入 crossorigin 屬性解決了這個問題。如果使用 crossorigin="anonymous",則相當于匿名 CORS;如果使用 `crossorigin=“use-credentials”,則相當于帶認證的 CORS。
既然 img 標簽能這樣做,為什么 script 標簽就不能這樣做?于是瀏覽器廠商就為 script 標簽加入了同樣的 crossorigin 屬性用于解決上述安全限制問題?,F(xiàn)在 Chrome 和 Firefox 對這個屬性的支持是完全沒有問題的。Safari 則會把 crossorigin="anonymous" 當做 crossorigin="use-credentials" 處理,結(jié)果是如果服務器只支持匿名 CORS 則 Safari 會當做認證失敗。由于 CDN 服務器出于性能的考慮被設計為只能返回靜態(tài)內(nèi)容,不可能動態(tài)的根據(jù)請求返回認證 CORS 所需的 HTTP Header,Safari 相當于不能利用此特性來解決上述問題。
總結(jié)
JavaScript 異常處理看起來很簡單,跟其它語言沒什么區(qū)別,但真的要把異常都捕獲了然后對屬性做分析,其實還不是那么容易的事情?,F(xiàn)在盡管有一些第三方服務提供捕獲 JavaScript 異常的類 Google Analytics 服務,但如果要弄明白其中的細節(jié)和原理還是必須自己親手做一次。
一、是否可變的區(qū)別:
html屬性中的值是不變的,dom屬性的值是變化的。
二、適用場合不同:
核心DOM適合操作節(jié)點,如創(chuàng)建,刪除,查找等;HTML DOM適合操作屬性,如讀取或修改屬性的值。
三、兩者對象不同:
核心DOM :
對象:Document,Node, ? ElementNode,TextNode,AttributeNode,CommentNode,NodeList
HTML DOM:
對象:image,Table,Form,Input,Select...HTML標簽對象化
擴展資料
使用javascript操作DOM屬性就是操作javascript對象的屬性。javascript對象的屬性是不需要聲明的。有多種方式可以訪問屬性,如下:
myImg.src = "xxxxxx" //使用“.”運算符
myImg["src"] = "xxxxxx" // 使用屬性訪問器
var propName = "src";? myImg[propName] = "xxxxxx" //屬性訪問器支持變量
注:1)因為提供了屬性訪問器,所以可以通過下面的方式遍歷一個DOM對象的所有屬性:
var result = "";
for (var p in myImg){
result += "屬性名:" + p + ",屬性值:" + myImg[p] + "\n";
}
標題名稱:javascript反查,js取反判斷
分享網(wǎng)址:http://m.rwnh.cn/article10/dsdhido.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供營銷型網(wǎng)站建設、建站公司、移動網(wǎng)站建設、做網(wǎng)站、云服務器、品牌網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)