当前位置: 首页 > 后端技术 > Node.js

花式调优接口:hexvsbase64

时间:2023-04-03 16:43:40 Node.js

背景作为你的前端,你可能经常吹嘘自己是个冷酷的API调用机器,调优框架API,调优服务端API;但下面的内容可能会让你震惊,至少这几天让我很崩溃。从10月份开始,我就接到要求把我们平台的数据同步到集团的另外一个平台,怎么办?通过开放的API!!!这个开放的API调整起来有多难?我大概描述一下对称加密,对方平台发给我一对秘钥;好像所有的API都会这样,毕竟安全第一!!!MD5计算,哦不,是MD5计算然后转base64;这实际上是正常的。为了防止数据传输被篡改,请求bodymd5加密也很常见;请求头摘要被签名,签名是什么鬼?消化是什么鬼?没错,还是为了安全起见,而且这个玩法很复杂,我没见过;只能调整线上环境,线下不行,什么??;但是最难的是环境是隔离的,就是不能跨机房调用。不可能),这说明什么?说明不能热更新,本地调整不可行?改一行代码,需要去预发布环境(预发布环境属于线上机房)部署一次(>5min),然后调整刚刚部署的界面,发现不对,然后再换一行代码,再部署,再调整,继续重复!!!严重地???可能你现在想知道,是哪个平台商提供了这个API,我悄悄告诉你,算了,你自己看吧:https://help.aliyun.com/docum...花哨的界面postman是个好东西一个工具,但是有时候postman也可能做不到它想做的事情(postwoman也是一样),比如今天要说的机房调用。所以,下面说的这些招式,在常规的前端开发中可能不会遇到,也不会用到,但是看看也不花钱,万一赚钱呢。招式一:动态传参通常我们无法调整服务端的API接口,通常只有两种情况:服务端是白痴,写了一个根本无法调整的接口(我这里不存在,因为传说是,至少他向我证明了网关是连通的);前端笨,参数没有按照说明来,所以我默认了我的笨方案,也就是服务器的输入参数,我通过我的接口动态上传,错了我改,听起来可能有点混乱,让我画一张图:有点草率。但事情并没有我想的那么简单。我真的很困惑,因为这个接口远不是正确设置参数那么简单。因为我要正确计算md5,正确设置请求头,正确签名;并且这些请求标头也需要动态更改。Withsolution2:interfaceproxy解决方案2:interfaceproxy代理,前端可能不陌生,webpack-dev-server有这个功能,多用于解决接口跨域。那么,为什么我需要动态传递参数呢?直接添加代理对我来说并不简单,所以解决方法是这样的:两行代码搞定://plugin.jsaddpluginexportconsthttpProxy={enable:true,package:'egg-http-proxy',};//在config.js中添加配置config.httpProxy={'/aapi':{target:'http://api-gateway.test.com',pathRewrite:{'^/aoneapi':''}}};这个方案听起来不错,有热更新和离线调试;但是因为我们平台底层有一些中间件,当目标平台响应400或者401时,我们的平台(node-server)会拦截返回一个302重定向,导致我看不到真正的错误响应目标平台,但是改变底层的拦截会发生很大变化,同时也会影响其他同事的开发。方案三:远程服务器直接调用鉴于之前的curl尝试,证明最直接的接口调用,最短的链接,可以避免最少的错误curl-v-XGEThttp://test.goaway.com/checkpreload-H'Authorization:APPCODEf7f526fd3adf2f38d46'因为NodeJs是一种脚本语言,不同于Java这种编译型语言。这时候,好处就体现出来了。考虑到服务器上有源代码,可以直接通过node命令调用接口调用,所以现在链接变成这样:我添加了一个文件(test.js),伪代码:constrp=require('request-承诺');const{createHash,createHmac}=require('crypto');asyncfunctionhandle(str=[]){//省略具体实现}//获取请求相关数据constarg=process.argv.slice(ArgStart);handle(arg);所以当我部署代码时,我可以运行nodetest.js...,就像:这样执行,我可以自定义响应体,你可以看到请求头是否符合规范,你可以清楚地看到发生错误时的错误响应;最重要的是,当我知道错误时,我可以直接在服务器上编辑代码,然后运行命令测试,这样可以节省很多时间。这一切的实现,都要归功于NodeJs这种脚本语言!!!分享知识:这次md5调试,我的卡点大致可以纠结在四个阶段:机房隔离,网络故障Invalidmd5InvalidsignalAuthenticationerrorsinceofoperatornot根据ak卡配置的最长时间是Invalidmd5;由于一开始官方提供了SDK,所以里面提供了md5的计算方法:staticgetContentMD5(body){consthash=crypto_1.createHash('md5');散列.更新(正文);returnhash.digest('hex');}但问题就出在这里。这个MD5计算和官方文档中说的不一致:可以看出md5计算后是base64方式编码的。官方SDK只需修改如下即可得到一致的结果:staticgetContentMD5(body){consthash=crypto_1.createHash('md5');散列更新(正文);returnhash.digest('base64');}那么digest方法的入参有什么秘密呢?NodeJs官方文档digestentry在crypto:0.1.92版本,typescriptentry定义如下;输入BinaryToTextEncoding="base64"|“base64url”|"hex"除了以上三个参数(0.1.94版本没有base64url选项),其实这个入参还可以为空,为空则返回Buffer,否则返回string,日常场景下的所有入参存在,因为我们持有一个Buffer是没有意义的,当它对helloworld进行md5计算时,得到的buffer是:那么为什么不要直接使用Buffer,因为对象不利于传输!!!base64vshex可以理解为base64vsbase16;所以当我们传入hex时,结果是:fc3ff98e8c6a0d3087d515c0473f8677,正好是上面的bufferstringification。并传入base64,结果为:/D/5joxqDTCH1RXARz+Gdw==因为Buffer本身是由一串十六进制数组成的,转成hex会很容易,但是要转成base64,需要重新编码关于base64编码:并不是所有在网络上传输的字符都是可打印的字符,比如二进制文件、图片等,Base64的出现就是为了解决这个问题。它是一种基于64个可打印字符(A-Z、a-z、0-9、+、/)表示二进制数据的方法;转码过程:首先将转换后的字符分成三个字节一组,每个字节占8位,所以一共24个二进制位,然后将二进制位分成4组,每组6个。在其中加两个0每组前面,每组从6到8个二进制位变化,共32个二进制位,即4个字节。最后根据Base64编码对照表得到对应的值(位数不足:位数由8bit转6bit时,不完整的6bit补0,没有对应6bit的8bit直接补=这里做个粗略的转换,十六进制结果为32个字符,每个字符为4个二进制数第一步:转换为二进制数:1111-1010-0011.....-0111-0111(32*4=128)第二步:将其转化为一组6位,再转化为一组三位的大组:111110-100011-.....-011101-11(7*3*6+2)第三步:补0,supplement=:00111110-00100011-....-00011101-00110000-=-=第四步:从对照表中转换字符:/-D-....-d-w-=-=至少开头和结尾都是一样的,套路应该没问题。至于什么时候用base64,什么时候用base16;对于md5计算,这个主要看服务器的心情!但是对于大字节流,比如文件,图片传输,会使用base64,因为可以节省流量,提高传输效率。什么是base64Url?base64Url也称为安全Base64,base64与base64的区别仅在于字符63和64的转换;由于“/”、“=”等是URL中的保留字符或不安全字符,因此如果在URL中直接传输Base64编码,保留字符和不安全字符会被%XX替换,给后端带来不便解码。如果不更换,会造成URL注入漏洞。所以base64Url的目的就是为了解决url中+,\,=的传输问题。写完一篇文章,要有仪式感,不能虎头蛇尾。最后让我感叹一下:做前端好难!!!欢迎关注我的前端公众号:前端黑洞