新聞中心
然后我就發(fā)現(xiàn)這個(gè)API接口有一個(gè)bug。并且根據(jù)它的現(xiàn)象,猜到它問題出在哪里。

創(chuàng)新互聯(lián)建站專業(yè)為企業(yè)提供郊區(qū)網(wǎng)站建設(shè)、郊區(qū)做網(wǎng)站、郊區(qū)網(wǎng)站設(shè)計(jì)、郊區(qū)網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、郊區(qū)企業(yè)網(wǎng)站模板建站服務(wù),十多年郊區(qū)做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。
我先來簡單描述一下現(xiàn)象。
假設(shè)我硬盤上現(xiàn)在有50個(gè)Markdown文件。現(xiàn)在我要把它發(fā)布到網(wǎng)站上。簡化代碼如下:
import glob
import requests
for path in glob.glob('blog/*.md'):
with open(path) as f:
article = f.read()
requests.post('https://xxx.yyy.com/post?token=abcasdf', json={'content': content})
發(fā)布完成以后,文章確實(shí)都已經(jīng)在網(wǎng)頁上出現(xiàn)了,并且每篇文章都能正常顯示。但我粗略瀏覽了一下,發(fā)現(xiàn)里面有一些文章的末尾帶上來我的微信公眾號二維碼。我不想讓公司的人知道我的公眾號,所以準(zhǔn)備修改一下文章。
有一些文章有二維碼,有一些沒有,一個(gè)一個(gè)改起來很麻煩,所以我做了兩步操作。首先寫了一個(gè)程序,掃描所有Markdown文件,發(fā)現(xiàn)二維碼就刪掉。然后,我直接在網(wǎng)站上把剛剛發(fā)布的所有文章都刪了(懶得去看哪篇有二維碼,哪篇沒有,干脆全刪了重發(fā))。
接下來,我再次運(yùn)行程序批量重新發(fā)布文章。2秒鐘以后發(fā)布完成。
本來一切看起來都很正常,但是當(dāng)我到網(wǎng)站上查看的時(shí)候,發(fā)現(xiàn)有很多文章點(diǎn)開以后,都提示『該文章已經(jīng)刪除』。
我一開始在想是不是我的程序?qū)懙貌粚?,漏掉了這些文章。我重新單獨(dú)一篇一篇發(fā)布這篇文章,API接口返回發(fā)布成功,可在網(wǎng)頁上還是顯示文章已經(jīng)刪除。
然后我一篇一篇檢查這些發(fā)布失敗的文章,發(fā)現(xiàn)有一個(gè)共同的特點(diǎn):他們是一開始就沒有二維碼的文章。相當(dāng)于這些文章我在網(wǎng)站上刪除以后原樣重新又發(fā)了一次。
那我就有了一個(gè)初步的猜測,大概知道原因是什么了:
因?yàn)槊科恼掠幸粋€(gè)docid,當(dāng)?shù)谝淮伟l(fā)布文章的時(shí)候,這個(gè)docid就是文章正文內(nèi)容的md5值。只要文章完全一樣,連續(xù)發(fā)多少次,它的docid都一樣。這樣就可以防止出現(xiàn)重復(fù)文章。(更新的時(shí)候,需要用戶主動(dòng)提供docid,避免重新生成新的)。
這個(gè)網(wǎng)站的刪除功能,肯定是假刪除。也就是當(dāng)我點(diǎn)了刪除文章的按鈕時(shí),文章其實(shí)依然在數(shù)據(jù)庫里面,只不過增加了一個(gè)字段removed=True?。網(wǎng)頁顯示文章的時(shí)候,查詢條件肯定是col.find({'removed': {"$ne": True}}),所以就不會(huì)把這些被軟刪除的文章顯示出來。
API發(fā)布新文章的時(shí)候,肯定使用的是更新操作。并且使用了upsert=True。
以MongoDB為例,這個(gè)API背后的邏輯肯定是這樣的:
def post_article(docid, article_info):
mongo.update_one({'_id': docid}, {'$set': article_info}, upsert=True)
upsert=True的作用,是先檢查數(shù)據(jù)是否存在,如果存在就更新,如果不存在就插入。
第一次發(fā)布的時(shí)候,文章不存在,直接插入,正常。如果用戶正常使用修改接口,修改了正文,因?yàn)橛脩糁鲃?dòng)提供了docid,所以也能正常更新。
但如果用戶先刪除了數(shù)據(jù),此時(shí)數(shù)據(jù)庫中,增加了一個(gè)字段removed=True?。然后用戶又原封不動(dòng)重新發(fā)一次文章。那么docid肯定還是原來那個(gè)。這條文章已經(jīng)在數(shù)據(jù)庫中存在了。于是逐一更新了每個(gè)字段。但是新發(fā)布的字段里面是沒有removed這個(gè)字段的,所以更新的時(shí)候不會(huì)更新它,它還在數(shù)據(jù)庫里面。所以就出現(xiàn)了發(fā)布成功,但是打開新聞?dòng)痔崾疚恼乱呀?jīng)刪除。
我去問了一下做這個(gè)API的同學(xué),果然它的bug原因跟我設(shè)想的一模一樣。
這個(gè)bug解決方法非常簡單,發(fā)布新文章的時(shí)候,把update_one?改成replace_one就可以了:
def post_article(docid, article_info):
mongo.replace_one({'_id': docid}, {'$set': article_info}, upsert=True)
當(dāng)前題目:一日一技:Bug分析,假刪除導(dǎo)致文章發(fā)布成功卻打不開的問題
標(biāo)題路徑:http://www.dlmjj.cn/article/djoceed.html


咨詢
建站咨詢
