当前位置: 首页 > 科技观察

一日一技:Bug分析,假删除导致文章发布成功却打不开的问题_0

时间:2023-03-16 11:05:15 科技观察

每日一技能:Bug分析,假删导致文章发布成功但打不开的问题。昨天这个内部博客开通了一个API,所以我要写一个Python程序来上传我所有的文章公众号。然后发现这个API接口有bug。并根据其现象,猜测问题出在哪里。我先简单描述一下这个现象。假设我的硬盘上现在有50个Markdown文件。现在我要把它发布在网站上。简化代码如下:/xxx.yyy.com/post?token=abcasdf',json={'content':content})发布完成后,文章确实出现在网页上,每篇文章都能正常显示。但是我快速浏览了一下,发现有一些文章的末尾有我的微信公众号二维码。我不想让公司里的人知道我的公众号,所以我要修改文章。有些文章有二维码,有些没有。一个一个改很麻烦,所以分两步操作。首先,我写了一个扫描所有Markdown文件并在找到时删除二维码的程序。然后,我直接把网站上刚发的文章全部删了(我也懒得看哪些有二维码,哪些没有,干脆全部删了重新发)。接下来,我再次运行程序以批量重新发布文章。2秒后释放完成。起初一切似乎都很正常,但是当我去网站查看时,发现点击很多文章后,都提示“该文章已被删除”。一开始我怀疑是不是我的程序写错了,错过了这些文章。我把这篇文章一篇一篇的重新发布,API接口返回发布成功,但是网页上还是显示文章被删除了。然后我一一查看这些失败的文章,发现它们有一个共同的特点:都是开头没有二维码的文章。相当于我在网站上删除了这些文章后重新发布。那么我就有了初步的猜测,大概知道是什么原因了:因为每篇文章都有一个docid,在文章第一次发布的时候,这个docid就是文章正文内容的md5值。只要文章完全一样,不管连续发多少次,它的docid都是一样的。这样可以防止文章重复。(更新时需要用户主动提供docid,避免重新生成新的)。本网站的删除功能一定是假删除。即当我点击删除文章的按钮时,文章实际上还在数据库中,只是增加了一个字段removed=True。在网页上显示文章时,查询条件必须是col.find({'removed':{"$ne":True}}),这样这些被软删除的文章就不会被显示。API发布新文章时,必须使用更新操作。并使用upsert=True。以MongoDB为例,这个API背后的逻辑一定是这样的:defpost_article(docid,article_info):mongo.update_one({'_id':docid},{'$set':article_info},upsert=True)upsert=True的作用是先检查数据是否存在,存在则更新,不存在则插入。第一次发表的时候,文章不存在,直接插入,正常。如果用户正常使用修改界面,修改了文本,由于用户主动提供了docid,也可以正常更新。但是如果用户先删除数据,数据库中会增加一个字段removed=True。然后用户原封不动地重新发布文章。那么docid一定还是原来的那个。这篇文章已经存在于数据库中。所以每个字段都一个一个更新。但是新发布的字段中没有removed字段,所以更新的时候不会更新,还在数据库中。于是就有了发布成功,但是打开新闻提示文章已被删除。问了做这个API的同学,结果发现bug的原因和我想象的一模一样。这个bug的解决方法很简单。发布新文章时,只需将update_one更改为replace_one:defpost_article(docid,article_info):mongo.replace_one({'_id':docid},{'$set':article_info},upsert=True)