成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

記一次由BOM引起的bug

cc17 / 1137人閱讀

摘要:今天團(tuán)隊小伙伴給了我一個配置文件,可以用如下替代畢竟內(nèi)容不是重點考慮到這個并不需要常駐,就沒有用來引用,因為模塊的緩存機(jī)制,勢必會導(dǎo)致內(nèi)存泄漏問題的發(fā)生,就采取了以下方式但是詭異的事情發(fā)生了,竟然報錯了此時一臉懵逼,就用了的方式試了一下發(fā)現(xiàn)

bug

今天團(tuán)隊小伙伴給了我一個json配置文件,可以用如下替代(畢竟內(nèi)容不是重點):

{
    "text": "this is a example"
}

考慮到這個json并不需要常駐,就沒有用require來引用,因為node模塊的緩存機(jī)制,勢必會導(dǎo)致內(nèi)存泄漏問題的發(fā)生,就采取了以下方式:

fs.readFile(`${__dirname}/y.json`, "utf8", function(err, str) {
  if (err) {
    throw err;
  }
  try {
    const data = JSON.parse(str);
    // ...
  } catch(err) {
    throw err;
  }
});

但是詭異的事情發(fā)生了,JSON.parse竟然報錯了???

Unexpected token ? in JSON at position 0

此時一臉懵逼,就用了require的方式試了一下發(fā)現(xiàn)一點問題都沒有,考慮到了團(tuán)隊小伙伴使用的windows,就去問了下他,得知這個jsonnotepad++寫的,加上之前寫php經(jīng)常遇到的BOM問題,就猜測這個bug由BOM引起,將讀出來的str轉(zhuǎn)成Buffer來看果然開頭是ef bb bf。下面先來看下今天說的這個BOM到底是個什么東西:

BOM

字節(jié)順序標(biāo)記(英語:byte-order mark,BOM)是位于碼點U+FEFF的統(tǒng)一碼字符的名稱。當(dāng)以UTF-16或UTF-32來將UCS/統(tǒng)一碼字符所組成的字符串編碼時,這個字符被用來標(biāo)示其字節(jié)序。它常被用來當(dāng)做標(biāo)示文件是以UTF-8、UTF-16或UTF-32編碼的記號。

說白了就是存在于文本文件的開頭,標(biāo)記出文件是依靠那種格式進(jìn)行編碼的,mac上應(yīng)該不存在,但是windowsnotepad++一般會帶有。大家也可以用python寫一個帶有BOM標(biāo)記的文件,來驗證這個問題:

import codecs

code = """{
    "x": 20
}
"""

f = codecs.open("y.json", "w", "utf_8_sig")
f.write(code)
f.close()

了解了產(chǎn)生原因以及BOM到底是什么,還有一個疑惑就是為什么用require引入可以?

require json做了啥

記得require是用的fs.readFileSync同步讀取的,為什么這個可以呢?猜測都是無用的,來看下node的源碼,找到了這段:

Module._extensions[".json"] = function(module, filename) {
  var content = fs.readFileSync(filename, "utf8");
  try {
    module.exports = JSON.parse(internalModule.stripBOM(content));
  } catch (err) {
    err.message = filename + ": " + err.message;
    throw err;
  }
};

看了上面的代碼可以非常明了,require在讀取之后,對字符串進(jìn)行了去除BOM的操作,來看下internalModule.stripBOM的實現(xiàn):

function stripBOM(content) {
  // 檢測第一個字符是否為BOM
  if (content.charCodeAt(0) === 0xFEFF) {
    content = content.slice(1);
  }
  return content;
}

至此問題已經(jīng)解決了,但是我還有一點不明白的是ef bb bfutf8的標(biāo)記,為什么會轉(zhuǎn)換為feff,這個不是utf16大端序的表示嗎?下面就來解決這個疑惑:

Unicode與utf8

先來講一下編碼的歷史,首先出現(xiàn)的表示字符編碼為ASCII,八位二進(jìn)制,可以表示出256種狀態(tài),英文用128個符號編碼就可以了,但是其他的語言卻無法表示,于是在一些歐洲國家,開始各自規(guī)定其表示,比如130在法語代表一個字符,俄語代表一個字符,這樣造成了0-127一致,而128-255可能會千差萬別;為了解決這種問題,國際組織設(shè)計提出了Unicode,一個可以容納全世界所有語言文字的編碼方案,Unicode只規(guī)定了符號的二進(jìn)制代碼,但是沒有規(guī)定該如何存儲,比如中文可能至少需要2個字節(jié),而英文只需要一個字節(jié)即可。utf8作為一種Unicode的實現(xiàn)方式被廣泛顎用于互聯(lián)網(wǎng)應(yīng)用中,utf8明確了編碼規(guī)則:

對于單字節(jié)的符號,將其第一位置為0,使用后面7位進(jìn)行表示,所以說英文utf8編碼與ASCII碼一致

對于n(n > 2)個字節(jié)的符號,第一個字節(jié)的前n為都設(shè)置為1,第n+1為設(shè)為0,后面字節(jié)的前兩位一律設(shè)為10,剩下的二進(jìn)制位,為這個符號的Unicode

可以參見以下對照:

字符字節(jié) Unicode符號范圍 utf8編碼方式
1 0000 0000 - 0000 007F 0xxxxxxx
2 0000 0080 - 0000 07FF 110xxxxx 10xxxxxx
3 0000 0800 - 0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
4 0001 0000 - 0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
5 0020 0000 - 03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
6 0400 0000 - 7FFF FFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

來看下feff轉(zhuǎn)化為ef bb bf,fs.readFileSync進(jìn)行了buffer -> string的轉(zhuǎn)換,buffer的編碼為utf8,而stringUnicode,根據(jù)上表計算下:

F E F F
1111 1110 1111 1111

根據(jù)其范圍,得出其utf8編碼:

1110 1111 1011 1011 1011 1111
E F B B B F

用代碼來實現(xiàn)下Unicode轉(zhuǎn)utf8的過程:

def UnicodeToUtf8(unic):
    res = list()
    if unic < 0x7F:
        res.append(hex(unic & 0x7F))
    elif unic >= 0x80 and unic <= 0x7FF:
        # 110xxxxx
        res.append(((unic >> 6) & 0x1F) | 0xC0)
        # 10xxxxxx
        res.append((unic & 0x3F) | 0x80)
    elif unic >= 0x800 and unic <= 0xFFFF:
        # 1110xxxx
        res.append(((unic >> 12) & 0x0F) | 0xE0)
        # all is 10xxxxxx
        res.append(((unic >>  6) & 0x3F) | 0x80)
        res.append((unic & 0x3F) | 0x80)
    elif unic >= 0x10000 and unic <= 0x1FFFFF:
        # 11110xxx
        res.append(((unic >> 18) & 0x07) | 0xF0)
        # all is 10xxxxxx
        res.append(((unic >> 12) & 0x3F) | 0x80)
        res.append(((unic >>  6) & 0x3F) | 0x80)
        res.append((unic & 0x3F) | 0x80)
    elif unic >= 0x200000 and unic <= 0x3FFFFFF:
        # 111110xx
        res.append(((unic >> 24) & 0x03) | 0xF8)
        # all is 10xxxxxx
        res.append(((unic >> 18) & 0x3F) | 0x80)
        res.append(((unic >> 12) & 0x3F) | 0x80)
        res.append(((unic >>  6) & 0x3F) | 0x80)
        res.append((unic & 0x3F) | 0x80)
    elif unic >= 0x4000000 and unic <= 0x7FFFFFFF:
        # 1111110x
        res.append(((unic >> 30) & 0x01) | 0xFC)
        # all is 10xxxxxx
        res.append(((unic >> 24) & 0x3F) | 0x80)
        res.append(((unic >> 18) & 0x3F) | 0x80)
        res.append(((unic >> 12) & 0x3F) | 0x80)
        res.append(((unic >>  6) & 0x3F) | 0x80)
        res.append((unic & 0x3F) | 0x80)
    return map(lambda r:hex(r), res)
# test
print UnicodeToUtf8(0xFEFF)

utf8轉(zhuǎn)Unicode只需要去除標(biāo)志位即可,這里就不在實現(xiàn)。

到此,終于清楚的可以和團(tuán)隊小伙伴說出bug的解決方法就利用上面的stripBOM

致謝

如有錯誤,還請指出!

Unicode與utf8 部分內(nèi)容參考自阮老師文章

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/89907.html

相關(guān)文章

  • 一次線上bug處理-mybatis一級緩存引起

    摘要:問題線上定時任務(wù)計算出的金額不對定位問題查看日志好像也執(zhí)行了但是金額為什么和數(shù)據(jù)庫的表里的不一致再查整個的定時任務(wù)日志日切日期 問題: 線上riskProvision定時任務(wù),計算出的金額不對 定位問題: 查看日志 4.13 riskProvision 2017-04-13 01:10:00.009 [org.springframework.scheduling.quartz....

    sean 評論0 收藏0
  • 一次低級并嚴(yán)重開發(fā)失誤

    摘要:而這一次的項目,原本以為開發(fā)挺順利的,但是開發(fā)完了,才發(fā)現(xiàn)自己犯了一個低級而嚴(yán)重的錯,這樣的一個失誤,我一直耿耿于懷。但是監(jiān)聽用戶退出頁面微信瀏覽器上面的那個返回或者關(guān)閉按鈕卻死活不行。也容易犯一些低級的錯誤。 1.前言 前端從事了超過兩年,修復(fù)了無數(shù)的bug,寫了無數(shù)的bug;挖了很多次坑,填了很多次坑;犯了很多次錯,彌補(bǔ)了很多次,學(xué)習(xí)了很多次。一般而言,對于bug、坑,都是修復(fù)完了...

    wudengzan 評論0 收藏0
  • 一次繪圖框架技術(shù)選型: jsPlumb VS mxGraph

    摘要:公司項目需要用到繪圖框架,繪圖部分以前是另一位同事負(fù)責(zé),用的是框架?;谝陨咸峒暗降姆N種原因,上年年末我做起了技術(shù)調(diào)研,希望能找到一個合適我們項目的繪圖框架。兼容性問題項目對瀏覽器兼容性比較寬松,瀏覽器兼容性問題不在考慮范圍之內(nèi)。 showImg(https://ws3.sinaimg.cn/large/006tKfTcgy1g0ppk2kkhxj30ka0b4gm5.jpg); 公司...

    longmon 評論0 收藏0
  • 一次繪圖框架技術(shù)選型: jsPlumb VS mxGraph

    摘要:公司項目需要用到繪圖框架,繪圖部分以前是另一位同事負(fù)責(zé),用的是框架?;谝陨咸峒暗降姆N種原因,上年年末我做起了技術(shù)調(diào)研,希望能找到一個合適我們項目的繪圖框架。兼容性問題項目對瀏覽器兼容性比較寬松,瀏覽器兼容性問題不在考慮范圍之內(nèi)。 showImg(https://ws3.sinaimg.cn/large/006tKfTcgy1g0ppk2kkhxj30ka0b4gm5.jpg); 公司...

    channg 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<