V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
harry890829
V2EX  ›  问与答

关于订单号的生成

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

    现在项目场景是, 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
    应该淘宝差不多就这么干的
    ck65
        32
    ck65  
       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 马蓉的微博头像
    killerv
        51
    killerv  
       2016-08-24 10:05:07 +08:00
    客户端生成订单号,这是什么人想出来的……
    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   ·   实用小工具   ·   2753 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 14:33 · PVG 22:33 · LAX 06:33 · JFK 09:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.