今天碰到了一個很有趣的bug修復赎瞎,在這里記錄一下怔毛。
這個bug是由于接收訂單推送接口沒有記錄住一個打印物流面單的API地址独悴,每一個訂單有一個物流追蹤號和對應打印物流面單的地址骗灶,需要修復沒有記錄到的數(shù)據(jù)艘策。API地址大概長這樣:
留意到唯一的不同是data_param中的某一段不一樣就可展示不同的物流面單
看著很有規(guī)律但是又一頭霧水况褪,總感覺是一個可反向解碼的編碼撕贞。運氣很好的是拿其中一段去各種試,最后發(fā)現(xiàn)這種是base64的編碼测垛,而不一樣的那一段就是追蹤號捏膨,那就有戲了。下面是反向解碼:
于是有了思路食侮,數(shù)據(jù)庫有追蹤號号涯,那就只需要把追蹤號轉換成base64碼,再把前后拼回去就好了锯七。
第一步链快,建encode函數(shù)。
發(fā)現(xiàn)sqlserver沒有直接的base64函數(shù)眉尸,于是搜了一下域蜗,然后在數(shù)據(jù)庫里建了2個函數(shù)。實際上這里只用到了encode函數(shù)噪猾。
CREATE FUNCTION [dbo].[f_base64_encode]
(@bin varbinary(max))
returns varchar(max)
as begin
return cast(N'' as xml).value('xs:base64Binary(xs:hexBinary(sql:variable("@bin")))', 'varchar(max)')
end
GO
CREATE FUNCTION [dbo].[f_base64_decode]
(@64 varchar(max))
returns varbinary(max)
as begin
return cast(N'' as xml).value('xs:base64Binary(sql:variable("@64"))', 'varbinary(max)')
end
GO
第二步霉祸,測試encode函數(shù)
很有意思的是,同一個encode函數(shù)袱蜡,轉換寫死的追蹤號和轉換數(shù)據(jù)庫中字段(這里cast和convert是同樣效果的)丝蹭,出來的結果是不一樣的。
當然第一反應是看一下坪蚁,這第三個字段解碼后是什么奔穿,發(fā)現(xiàn)居然每個都是幫我加了個空格,如下圖迅细。
這中間還出了一個小插曲巫橄,在第一個在線轉換工具上解碼后看起來和用字符串NjQwMDIyODUyODQ1
解碼是一樣的淘邻,實在不信邪換了一個工具才發(fā)現(xiàn)是不一樣的茵典,上圖已經(jīng)和第一個圖中的在線解碼工具不一樣。
什么問題呢宾舅?
那當然是有問題统阿,后來發(fā)現(xiàn)是nvarchar的使用問題彩倚,nvarchar每個字符用2個字節(jié)存儲,而'640022852845'
的數(shù)據(jù)類型是varchar扶平,強行被教育了一波varcahr和nvarchar的區(qū)別帆离。
解決方案
怎么解決?想了各種辦法结澄,嘗試了各種手段之后哥谷,發(fā)現(xiàn)改數(shù)據(jù)表中字段的數(shù)據(jù)類型為varchar就好了,因為存的是追蹤號麻献,不會有需要2個字節(jié)才能存的字符(如中文们妥、韓文等非Unicode字符)。
第三步勉吻,更新數(shù)據(jù)
更新語句早就寫好监婶,就是拼上去,要不是被第二步的nvarchar和varchar問題卡住齿桃,1小時也就收工了惑惶。
UPDATE ODR_OrderMain SET Prediction_ERROR =
'http://api.yl-scm.com:22220/yunlu-order-web/rotaPrin/rotaPrintAction!doPrint.action?data_param=eyJjdXN0b21lcmlkIjoiUzAwMDAxQzEzNiIsImJpbGxjb2RlIjoi'
+ dbo.f_base64_encode(cast(TrackingNo as varbinary(50))) + 'IiwibGFuZ3VhZ2UiOiJNWVMifQ=='
WHERE Prediction_ERROR = 'http';
驗證后發(fā)現(xiàn)數(shù)據(jù)庫中的API能正常調用,那就OK啦~