关于订单号的生成 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
harry890829
V2EX    问与答

关于订单号的生成

  •  
  •   harry890829 2016-08-23 15:45:22 +08:00 9546 次点击
    这是一个创建于 3338 天前的主题,其中的信息可能已经有所发展或是发生改变。

    现在项目场景是, pc 客户端生成订单号传给后端,之前使用的是微秒级的时间+随机数,但是依旧发生了重复情况,现在想要优化这个算法,要求订单号中只包含数字,长度小于 30 。

    后来想到两种方法: 1.YYMMDDhhmmss+mac 地址(转成 18 位十进制),经过讨论, mac 地址可以进行修改,时间也不一定是确定的,假设场景,客户在 12:00 支付完成之后,发现自己时间快了半小时,然后回调了,这样在 11:30 到 12:00 之间就有可能重复。

    2.YYYYMMDDhhmiss+毫秒+微秒+IP 尾 4 位+6 位随机数,其中 6 位随机数种子采用( mac 地址前三位前补 00 )与( mac 地址后三位后补 00 )进行异或得出。这个方法大家觉得只是极大的减少的几率问题,但是并不能避免重复的问题

    也有同事提到了, guid 来做,但是订单号要求纯数字,现问下如何解决此类问题,多谢 开发语言 c/c++

    第 1 条附言    2016-08-24 14:18:39 +08:00
    多谢大家的吐槽和建议,我已经让领导看了这个帖子,现在暂定做法就是极大减少重复几率,然后后期在服务器修改,以优化
    63 条回复    2016-08-24 14:23:35 +08:00
    jugelizi
        1
    jugelizi  
       2016-08-23 15:56:02 +08:00
    客户端。。。大作死啊
    harry890829
        2
    harry890829  
    OP
       2016-08-23 15:57:17 +08:00
    @jugelizi 哎,现在这个事情已经不可逆了……要是再服务器生成订单号需要修改大量的模块……
    loading
        3
    loading  
       2016-08-23 16:00:37 +08:00 via Android
    Uuid 算法
    loading
        4
    loading  
       2016-08-23 16:02:05 +08:00 via Android
    不用大改吧……入服务器单独设置个接口,申请一个 id 返回,你后面的流程都没变……
    egen
        5
    egen  
       2016-08-23 16:02:57 +08:00
    你们有 30 个数字, YYMMDDhhmm 长度只有 10 ,后面 20 个全部随机,重复的几率可以忽略,比你加毫秒 mac 什么的重复几率小多了
    lincanbin
        6
    lincanbin  
       2016-08-23 16:02:59 +08:00
    GUID 从二进制映射到十进制,大概需要 35 位整数,你要求长度小于 30 ,其实已经很接近了。
    再多加几位,或者心大点,砍掉 GUID 的几位。
    allce231
        7
    allce231  
       2016-08-23 16:03:35 +08:00
    客户端。。。大作死啊!!!!
    egen
        8
    egen  
       2016-08-23 16:04:39 +08:00
    因为客户端的时间不可信,记录秒和毫秒也没什么意义
    harry890829
        9
    harry890829  
    OP
       2016-08-23 16:05:26 +08:00
    @loading 我也想到这个情况,其实我完全可以让服务器开一个接口给我,然后我每次要生成订单号的时候,问服务器要就好了,不过貌似后端不想加这个接口

    @egen 这个貌似领导不能接受……

    @lincanbin guid 映射到十进制?我去看看,多谢了
    qian0206
        10
    qian0206  
       2016-08-23 16:06:10 +08:00
    在服务端弄个接口专门给客户端调用获取订单号不就行了
    harry890829
        11
    harry890829  
    OP
       2016-08-23 16:06:36 +08:00
    @allce231 都是泪……不知道项目启动的时候为什么这么规划
    @egen 是啊,客户端时间不可信, mac 也不是一个可信的值,所以感觉太蛋疼
    lincanbin
        12
    lincanbin  
       2016-08-23 16:09:38 +08:00
    订单号这种东西你们都敢客户端生成,心很大啊。
    lincanbin
        13
    lincanbin  
       2016-08-23 16:17:39 +08:00
    @harry890829
    噫,我前面算错了, GUID 映射成十进制,是最多需要 39 位整数。

    例如说 GUID ,{99D66A96-4CCD-2944-9A3C-9D583513897A},转十进制后就是 204485196726229962288084266002268806444 。

    你看着办吧。
    loading
        14
    loading  
       2016-08-23 16:20:59 +08:00 via Android
    如果让后台做个订单 id 的接口都搞不定,你们公司也就玩完了。
    xinyewdz
        15
    xinyewdz  
       2016-08-23 16:38:25 +08:00
    用户 id+时间+随机数。这样还会重复?
    terence4444
        16
    terence4444  
       2016-08-23 16:45:51 +08:00 via iPhone
    让客户端提交时检测是不是有重复号码,有的话重新生成一个?
    dong3580
        17
    dong3580  
       2016-08-23 17:08:26 +08:00
    @harry890829
    客户端怎么改都会有可能有重复,还是服务器端保存那里将收到的订单号运算一下 重新生成一下呀,不就好了,
    BuilderQiu
        18
    BuilderQiu  
       2016-08-23 17:14:18 +08:00
    我比较关注价格也是客户端算好传过去的吗?
    如果是,分享下客户端下载地址。


    然后,客户端生成订单 ID 这种方案是谁批的。。。设计方案讨论能通过。。

    治标就各种想办法减少重复数据,治本的办法还是服务器生成,沟通解决吧。
    yao978318542
        19
    yao978318542  
       2016-08-23 17:19:31 +08:00
    @allce231 你这个头像作大死
    allce231
        20
    allce231  
       2016-08-23 17:19:59 +08:00
    后端判断订单号重复 如果重复重新生成一个 id 给它
    sunshinewu85
        21
    sunshinewu85  
       2016-08-23 17:34:21 +08:00
    按楼主现在的意思,后端是不愿意提供任何生成及检测支持,全靠客户端去整,呵呵,这也理解,谁都不愿在自己管辖的地盘补上一脚,否则一出问题,把全问题都推过去了。。。可是在客户端无论怎么整,其实都已经在拆东墙补西墙了,还不是亡羊补牢。目前亡羊补牢靠谱的还是这两个方案较为合适吧:
    1 、找个能拍板让服务端改的人来,从服务端拿 ID 。有些业务,纵使现状改起来麻烦,也好过后续引出更多麻烦;
    2 、服务端不提供生成,那总得提供个检测吧~话说回来,都检测了,干脆服务端生成一起了吧,毕竟一劳永逸啊 <img src=" " class="embedded_image" border="0" />
    xmh51
        22
    xmh51  
       2016-08-23 17:34:56 +08:00
    额。不是办法的办法,服务器生成订单号传给客户端,客户端再上传到服务器。另一种 YYMMDDhhmm +随机数。但是被你否了。 另外随机和重复不是等同的,随机值不能避免重复。你还是在服务器生成订单号比较好。客户端怎么也不可能知道服务器上面是否有重复的订单号。
    finian
        23
    finian  
       2016-08-23 18:03:53 +08:00
    客户端再怎么整都可能会有问题(合法性、安全性),这事儿必须服务端来整。
    harry890829
        24
    harry890829  
    OP
       2016-08-23 18:22:57 +08:00
    @lincanbin guid 的情况我再看看能不能支持,多谢

    @loading
    @qian0206
    @sunshinewu85
    @xmh51
    @finian
    也不是没有想过服务端只开一个生成订单的接口,让客户端调用,但是本来一次的能够完成的动作变成了两次完成,这样失败的情况也就大幅度增加了,于是直接被否决

    @xinyewdz 用户 id 是本地 id ,并不唯一,或者说大家都是重复的

    @terence4444
    @dong3580
    @allce231
    现在目前的情况是服务器收到相同的订单号就会直接拒绝,也就是说服务器收到的第二个订单会被拒绝并返回订单号重复,目前的解决就是让前端重新发起一笔

    @BuilderQiu 哎,金额也是前端送的啊,不过我们后端有相应验证,并无大碍

    感谢大家,我倾向于方案二来做了,毕竟几率已经很小,关于 guid 的情况,我上报一下,看看是不是有定论
    sc3263
        25
    sc3263  
       2016-08-23 18:29:30 +08:00
    加个代理模块吧。客户端发消息到代理,代理那边计算好订单号,加到消息里,然后转发给服务端。

    还是得服务端改。不过改动能小很多。
    dong3580
        26
    dong3580  
       2016-08-23 18:49:41 +08:00 via Android
    @harry890829
    订单重复谁发出的?服务器对吧,它都知道重复了还不自动重新生成一下订单号,也是醉了。
    scnace
        27
    scnace  
       2016-08-23 19:03:38 +08:00 via Android
    用户 id 做 hash?
    HunterPan
        28
    HunterPan  
       2016-08-23 19:07:27 +08:00
    @allce231 你的头像好像在哪见过..
    hinate
        29
    hinate  
       2016-08-23 19:12:41 +08:00
    客户端的时间戳是不可信的。。。
    abelyao
        30
    abelyao  
       2016-08-23 19:14:00 +08:00 via iPhone
    客户端把不带订单号的数据提交给服务端,由服务端来生成订单号,反馈结果给客户端的时候,把订单号一起带上。这样仍然是一次请求。
    guizer
        31
    guizer  
       2016-08-23 19:37:43 +08:00 via iPhone
    前缀+时间+uid
    应该淘宝差不多就这么干的
    mogita
        32
    mogita  
       2016-08-23 19:43:59 +08:00
    中心化的发号机,别让客户端生成 id 。
    jon
        34
    jon  
       2016-08-23 21:45:30 +08:00
    客户端生成订单号服务端全盘接受吗,不检查怎么避免问题,检查了为什么不直接服务端生成
    ihuotui
        35
    ihuotui  
       2016-08-23 22:03:57 +08:00
    设计有问题,怎么补都不完美,再加一个接口,客户端获取服务器的全局唯一序号(不用别人教了吧,不过也不算很难或者很简单),然后剩下的逻辑和原来一样。
    以后的项目再写第二版,重写。
    popok
        36
    popok  
       2016-08-23 22:55:18 +08:00
    正常用户的用户使用出现重复的概率很小,就怕别有用心的人,毕竟你的订单号在客户端生成
    caola
        37
    caola  
       2016-08-23 23:50:18 +08:00
    一切客户端传入的数据,都有可能是是不可靠的。要是你内部人员使用就无所谓,
    如果是面向公众用户使用的话,做得安全一点是好的,毕竟可能会有那么一些别有用心之人。
    ljbha007
        38
    ljbha007  
       2016-08-24 00:08:20 +08:00
    客户端做的任何安全措施都是没有用的
    Perry
        39
    Perry  
       2016-08-24 01:18:55 +08:00
    @allce231 头像不错
    wavingclear
        40
    wavingclear  
       2016-08-24 01:47:10 +08:00 via iPad
    微秒级加随机数还有重复,这就是尝试攻击了,客户端还改啥
    gkiwi
        41
    gkiwi  
       2016-08-24 03:20:43 +08:00
    @yao978318542
    @Perry
    @HunterPan

    头像是什么梗。。求科普
    imnpc
        42
    imnpc  
       2016-08-24 08:10:57 +08:00
    客户端生成订单号 这么作大死的办法谁想出来的?
    客户端只允许传输关键类数据 例如商品 ID 数量
    其他涉及到安全的一律服务端控制...
    likai
        43
    likai  
       2016-08-24 08:27:20 +08:00
    客户端时间随便可以更改。拿来生成订单号合适么?
    gkiwi
        44
    gkiwi  
       2016-08-24 08:54:54 +08:00
    本来想写点的客户端怎么避免和处理的,但是这个锅不应该让客户端背!
    GKLuke
        45
    GKLuke  
       2016-08-24 09:00:59 +08:00
    客户端就不要调用本地时间了,调用网络时间或者服务器时间,那就不存在时间回调了。
    当然,永远不要相信前台数据,起码都要滤一边真伪啊。
    Clarencep
        46
    Clarencep  
       2016-08-24 09:04:48 +08:00
    订单号居然在客户端生成,这是在开玩笑吗
    wanttofly
        47
    wanttofly  
       2016-08-24 09:21:30 +08:00   1
    @gkiwi 头像的梗:这马容易劈腿。。。
    yuankui
        48
    yuankui  
       2016-08-24 09:34:04 +08:00
    这种问题,网上解决方案不是一大堆吗?

    你不是应该发一个帖子说你发现了哪些方案,然后让大家评价一下各个方案的优劣吗?
    GavinJ
        49
    GavinJ  
       2016-08-24 09:40:08 +08:00
    客户端生成订单, 新鲜~~~~
    DrJoseph
        50
    DrJoseph  
       2016-08-24 09:41:48 +08:00   1
    @gkiwi 马蓉的微博头像
        51
    killerv  
       2016-08-24 10:05:07 +08:00
    客户端生成订单号,这是什么人想出来的……
    killerv
    ThreeBody
        52
    ThreeBody  
       2016-08-24 10:23:19 +08:00 via Android
    天啊,订单号让前端生成已经是很严重的设计缺陷了,金额也让前段发?你后台有验证还要前段发一次?
    就这两个,我觉得你们系统可能还有很多坑。
    我想问问,我看到你说前端的用户 id 是一样的,你们前端难道不用用户登录的?就是可以匿名下单?
    是不是类似那种, 1688 元的 iphone 6s ,然后输入名字,地址,电话就直接下单那些?
    微妙级的订单都可能重复,加个 uuid ,这样应该就够的了。 uuid 碰撞几率这么低,加时间前缀,应该是够的了。
    pljhonglu
        53
    pljhonglu  
       2016-08-24 10:45:38 +08:00
    服务器的锅为什么要你来背。。。
    southwolf
        54
    southwolf  
       2016-08-24 10:54:23 +08:00
    LZ 赶紧来爆一下产品名字,组织 V2 群众薅羊毛去啊…… iPhone6s 点击就送啊
    damean
        55
    damean  
       2016-08-24 11:00:08 +08:00
    @harry890829 “本来一次的能够完成的动作变成了两次完成,这样失败的情况也就大幅度增加了”
    这个“大幅度”有统计过吗?
    为啥会失败呢?失败了还可以在尝试几次的。
    romisanic
        56
    romisanic  
       2016-08-24 11:01:02 +08:00
    如果改客户端订单号生成规则可行,意味着大家的客户端都要更新,既然如此,为什么不直接改成后端生成,这样所有客户端使用的订单号实际上是从一个位置生成的,也就不会再有重复的顾虑。哪怕后续有需要修改的地方,那也只需要直接修改服务端就可以了。
    22too
        57
    22too  
       2016-08-24 11:07:41 +08:00
    我们目前的做法,毫秒级时间 + 随机数 + 用户 id 。也就是除非这个用户故意重复,用户直接是隔离的。目前没有发现问题。
    williamx
        58
    williamx  
       2016-08-24 11:36:19 +08:00
    上面的说得没错,把用户 id 加上,基本都不会出现重复的问题。
    hitmanx
        59
    hitmanx  
       2016-08-24 12:52:32 +08:00
    如果把本地时间换成通过网络服务器获取时间呢?这样精确到毫秒,应该没有重复性的问题了吧,除非用户 hack ,不过那就是是整个架构问题了,反正现在也有这个问题。
    maxmilia
        60
    maxmilia  
       2016-08-24 13:25:20 +08:00
    用户 ID 直接给的话会被人知道用户规模,所以加个密
    SlipStupig
        61
    SlipStupig  
       2016-08-24 14:06:44 +08:00
    如果是单纯冲突的话转成 MD5 或者 SHA1 转一下,如果是破解,只能用 VMProtect 这类软件延缓一下,基本上在客户端是挡不住的
    harry890829
        62
    harry890829  
    OP
       2016-08-24 14:23:16 +08:00
    @sc3263 这个方法比较好,我也向领导反映了这个方案
    @dong3580 服务器发现重复直接拒绝,前端重新发起就好
    @scnace 用户 id 重复的
    @flyingfz 多谢,没想到汤不热上也有技术性文章……
    harry890829
        63
    harry890829  
    OP
       2016-08-24 14:23:35 +08:00
    上面各位不一一回复了,在这里感谢大家给出的建议……
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5486 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 07:26 PVG 15:26 LAX 00:26 JFK 03:26
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86