引子
坚持了20天,终于还是做了一个艰难的决定--把媳妇和娃送到了丈母娘家。
前些时间,老妈有事儿回了四川,给了我和媳妇独自抚养娃的机会,我知道这将是一个巨大的挑战。
因为一些知道的和不知道的原因,娃的湿疹比较严重,晚上老睡不踏实,得整晚拍着,哄着,实在没辙了,就得抱着睡,不然就不停的挠头呀,肚子的。。
白天除非抱着,根本睡不了一会儿,醒了没人看着,也是有事儿没事儿挠自己。根本离不开人...看着娃身上的湿疹,以及来不及好的挠痕,心里真是奔溃的。
还得到处寻医问诊,泡中药,涂药膏,抹茶油...官方的,民间的... 都是3个字:然并卵。
又值搬新家,更是忙得不可开交,与媳妇在杭州奋斗了6-7年,总算是有了自己的家,只是全然没空喜悦一下,反倒时房贷的压力总记在心上。
媳妇几度落泪,这不是矫情,一则是为自己孕期没管牢嘴,满月又吃了虾而自责;二则吃不好,睡不好,身心都是承受巨大压力,就是上个洗手间都得把娃哄睡了。
话说回来,也是正是这短短的20天,方才对“当家才知柴米贵,养儿方知父母恩”,有了切身的感受,对父母的嘘寒问暖不再厌烦,而真正心怀感恩。这个认知与媳妇的意见终于空前的一致了 :)。
跨出了丈母娘家门,挥手告别妻儿时,心头一紧,眼眶微酸,眼泪几乎夺眶而出...是了,这就是离别。也终于理解了,母亲每次送我出远门时,总是忍不住的哭泣。
—————————— 生活感悟,借此叨叨,回归主题——————————
背景
之前写过一篇关于同步饿了么订单的文章《订餐系统之同步饿了么商家订单》,是介绍如何通过 饿了么OpenAPI 同步饿了么商家订单。此版本最大的弊端便是每次要绑定商家都需要发邮件给他们,绑定商家是一个频繁的操作,但是他们邮件处理的速度又较为缓慢,有鉴于此对接人的几乎都是望而却步,像早期的淘点点,及新开美团外卖开放平台,都是以商家登录授权方式绑定,完全是开发商与商家自助就可以完成。前些天,饿了么OpenAPI2.0 总算是千呼万唤始出来了。赶紧注册,认证。于是有了这篇文章。
申请
先上开放平台网址, https://open.shop.ele.me/openapi《饿了么开放平台》, 首先,你得注册成为开放者,这个过程不用截图了吧。然后 开发者资质认证,这个按要求填写相关信息,上传相关资料等他们审核了。
几个工作日审核通过后,你们会看如下信息,就可开始进入下一步操作了。
创建应用
对接了美团后,才知道可以创建应用是多么方便一个功能,不然来一个客户,又得重新注册账号,走申请的流程,漫长而痛苦。饿了么OpenAPI2.0 可以创建多个应用,每个应用独立运行,减少了很多不必要的麻烦。
进入开发都中心,即可开始新建应用,输入几个基本信息,应用就创建好了。
接下来可以配置沙箱环境了,点击查看应用,进入“沙箱环境”选项卡。设置好 回调地址URL(商家授权后回调通知地址),推送URL(新订单,订单状态变化等通知地址),推送消息(选择要接收的通知类型)。配置部分到现在就结束了,接下变是上代码了。
,
商户授权
准备写代码之前,还是习惯性的去找下SDK,有SDK肯定会事半功倍的,只是不看不知道,一看真又感觉被默默的鄙视了一下下。提供了5种语言,都没有.net。好吧,别的咱不敢说,写代码还是会的。
初略看了文档知道授权流程采用国际通用的OAuth2.0标准协议作为商户身份验证与授权协议,之前对接QQ登录,微信公从平台,流程几乎类似,轻车熟路,已经有代码修改几个配置与json对应的实体,分分钟就完成了前面4个流程,流程图如下,核心代码也贴上来了
/// <summary> /// 授权 /// </summary> /// <param name="callbackurl"></param> public ELEAuth(HttpContext _context) { context = _context; parameters = new Hashtable(); singparameters = new Hashtable(); } /// <summary> /// 返回授权url /// </summary> /// <param name="shopid"></param> /// <returns></returns> public string GetAuthURL(int shopid) { string callbackurl = appconfig.authcallbackURL; string OAuthurl = appconfig.authurl + "?response_type=code&client_id=" + Hangjing.EleAPIV2.appconfig.Key + "&redirect_uri=" + context.Server.UrlEncode(Hangjing.EleAPIV2.appconfig.authcallbackURL) + "&state=" + shopid + "&scope=all"; return OAuthurl; } public access_tokenInfo getToken() { access_tokenInfo token = new access_tokenInfo(); parameters.Add("grant_type", "authorization_code"); parameters.Add("code", context.Request["code"]); parameters.Add("redirect_uri", appconfig.authcallbackURL); parameters.Add("client_id", appconfig.Key); string Authorization = appconfig.Key + ":" + appconfig.Secret; byte[] bytes = Encoding.UTF8.GetBytes(Authorization); HttpItem objHttpItem = new HttpItem() { Authorization = "Basic " + Convert.ToBase64String(bytes), URL = appconfig.tokenurl, Encoding = "utf-8", Method = "POST", Postdata = getPostDatan() }; HttpHelper objhttp = new HttpHelper(); objhttp.isToLower = false; Hangjing.AppLog.AppLog.Info("getToken:" + getPostDatan() + " url=" + appconfig.tokenurl + " Authorization=" + Convert.ToBase64String(bytes)); string returnmsg = objhttp.GetHtml(objHttpItem); Hangjing.AppLog.AppLog.Info("getToken:" + getPostDatan() + " msg=" + returnmsg + " Authorization=" + Convert.ToBase64String(bytes)); token = JsonConvert.DeserializeObject<access_tokenInfo>(returnmsg); if (token != null) { token.shopid = Convert.ToInt32(context.Request["state"]); } return token; }
回调地址URL指向的地方 只要如下调用就可以了。
ELEAuth auth = new EleAPIV2.ELEAuth(Context);
access_tokenInfo token = auth.getToken();
整个过程就一个地方要注意下:HTTP header中需要携带Authorization请求头,Basic值的算法如下(+号表示字符串连接) base64_encode(key + ":" + secret),具体的写法在上面的代码已经有了。大伙儿稍微留意下就过了。
话说回来,为什么是前面4个流程分分钟,独少了第五个呢,是了,第5个里面有一个计算签名的过程,几乎是第一次遇到这样的签名方式,过程较为麻烦,容易出错,之前也有几个园友也问到签名的事儿,所以这里单独拿出来。
签名算法
对接接口,签名总是较为麻烦的一点,相关文档如下点这里,如果想了解流程,可以自行查看。流程很长,这里就不写了,几个地方要注意的如下:
1,签名的参数,只包含 JSON对像,metas和params 的属性。当然,params可能没有属性,忽略就可以了。
2,使用"key=json_encode(value)"方式进行字符串拼接,这就得要求 参数的类型 要与文档里匹配,long与string json_encode后的值是有区别的。比如 json_encode(123) = 123,而 json_encode(“123”) =“ 123”,这就直接导致用于加密的内容都不同了。
其他的什么排序,action + token + secret,md5等等按正常流程走就可以了,没有坑了。
到这里,就只剩代码,签名算法代码如下:
//构建签名参数,注意 timestamp 类型是 int64 singparameters.Add("app_key", appconfig.Key); singparameters.Add("timestamp", Convert.ToInt64(Timestamp)); /// <summary> /// 签名 /// </summary> /// <returns></returns> public string createMD5Sign(string action, string token) { StringBuilder sb = new StringBuilder(); ArrayList akeys = new ArrayList(); foreach (var item in singparameters.Keys) { akeys.Add(item + "=" + JsonConvert.SerializeObject(singparameters[item]) + ""); } akeys.Sort(); foreach (string k in akeys) { sb.Append(k); } string signstep = action + token + sb.ToString() + appconfig.Secret; Hangjing.AppLog.AppLog.Info("createMD5Sign:oldsignstep=" + signstep); signstep = Utils.MD5(signstep).ToUpper(); Hangjing.AppLog.AppLog.Info("createMD5Sign:signstep=" + signstep); return signstep; }
第5个流程的文档在这里,主要是获取商户信息,与系统商家对应好,我是通过state参数传系统商家编号,因为state会原样回传回来。
计算好签名,这个流程就完成大半了,剩下注意如下:
1, Content-Type = application/json;charset=utf-8,
2, id 参数值为 Guid.NewGuid().ToString()
3,post的参数要是josn 格式。参数在系统里是用 Hashtable 保存的,只要一句话就可以转成Json -- JsonConvert.SerializeObject(parameters);
做了以上操作,此流程80%的情况就OK了。最后上几个实际流程图
接收订单参数,查询订单信息
设置好接收推送的url,根据通知类型和内容进行相应的逻辑操作,比如收到商家确认订单通知,就把订单加入系统,订单取消通知就把系统中订单相应取消。
完成了签名算法,其他的接口对接就是水到渠成的事儿了,根据json生成实体,替换参数,很快就可以完成其他接口了。
接收通知代码如下,特别注意就是消息体是以流形式推送过来的。另外还有一个情况可能大家都会遇到:创建应用后,会生成测试商家,商家的商品全是1毛的,你测试几单后,饿了么会认为商家在刷单,以后提交订单就直接取消了,无法测试,后来咨询的了客服,说是商品要大于1元才不会自动取消,这样就可以测试新订单推送,商家接单推送,然后再把订单取消,支付的金额就自动退回来了,
HJlog.toLog(" ele2.0推送"); System.IO.Stream stream = Request.InputStream;//这是你获得的流 if (stream != null && stream.Length > 10) { Hangjing.AppLog.AppLog.Info("stream.Length :" + stream.Length); string jsondata = ""; using (StreamReader reader = new StreamReader(stream)) { jsondata = reader.ReadToEnd(); ; } pushMessageInfo notice = JsonConvert.DeserializeObject<pushMessageInfo>(jsondata); switch (notice.type) { case 14: case 15: case 17: case 23: case 25: case 35: ////订单取消 { ordermessageinfo pushorder = JsonConvert.DeserializeObject<ordermessageinfo>(notice.message); string sys_orderid = "e" + pushorder.orderId; new Custorder().AddOrderRecord("e" + sys_orderid, 5, "ele", "饿了么取消了订单"); string sql = "update Custorder set OrderStatus=5 where OrderID='" + sys_orderid + "';update shopeleCustorder set OrderStatus=5 where OrderID='" + sys_orderid + "'"; WebUtility.excutesql(sql); } break; case 12: //接收订单 { ordermessageinfo pushorder = JsonConvert.DeserializeObject<ordermessageinfo>(notice.message); //获取token taobaoAPIAcountInfo token = new taobaoAPIAcount().GetList(1, 1, "linkurl='"+notice.shopId+"'", "id", 1).FirstOrDefault(); if (token == null) { Hangjing.AppLog.AppLog.Info("商家:" + notice.shopId + "未找到授权信息,orderid=" + pushorder.orderId); } else { ELEShopV2 eleshop = new ELEShopV2(Context); OrderResult rs = eleshop.getOrder(pushorder.orderId,token.pic); } } break; default: break; } }
上线
对接完成后,在 设置好 正式环境 的相关参数,提交审核,至此对接就基本完成了。订单同步进入系统后,就是我们的调度系统派上用场了。通过自动调度规则,让配送员自己抢单,几乎都不用客服调度了,大家还抢的不亦乐乎。以下是某客户实时效果图。
到此,终于实现了几个平台订单同步,总算是了了一件心事儿,还少百度外卖?直接忽略了,听商家说百度外卖半个月都不来个订单,连业务员都联系不上了。
对接流程就完结了,希望对那些想要对接的人能有些帮助,所有流程都是亲测,绝对童叟无欺。
结语
又到夏天了,猛然发现大学4年,每天6点起来练出来的腹肌早已紧密的团结在了一块儿,确实做我们一行的,每天上班,加班加起的得坐10几个小时,如疏于锻炼,不出3年,基本都得长肉肉的。于是,趁着媳妇回娘家,我开始了找回腹肌计划,希望她回来时,看到一个不一样的我。【她一直想看我有8块腹肌的样子 :)】
一,早上6:30起床,做好中午的饭,带去公司(外卖太贵了,也不是特别好吃),顺道在工商大学打30分钟篮球。去上班刚好。
二,晚上22:30-23:00之间 从公司跑回家,全程4公里,绕一下可以有5-6公里。(再晚点,就只能骑车了)
计划之初,内心也会抵触,反倒是执行2个月后,一切都变得自然而然,成了生活的一部分了。顺带还学会炒菜,当然了,我通常只放油盐,最多加点豆油,味道就那样了 :)。
到现在跑5公里基本不费多少力,有时还故意再绕一圈小区。唯一麻烦的就是要背着早上带的两个饭盒,权当负重吧。下面是一张最近的跑步记录,下一步就是挑战10KM了,我的终极目前是全马(哈哈)。另外,如果你也要想跑起来,一定注意跑前热身,跑后拉伸。
之前听别人的小密圈挺火,也下载玩了下把,创建了一个同步饿么订单的圈子,设置了付费50元加入(付费圈子最低50),抱着玩玩的心态,分享给了之前咨询饿了么接口微信好友,万万没想到,还真有几个人加入了,说是“作为支持你的分享”这也算是意外的惊喜吧,钱不多,背信任的感觉满好的。在此,也谢过几位了哈。
成为一名优秀的程序员!