API网关管理

[TOC] # 总体介绍 proxy阶段是生命周期的第2步,主要功能是对请求参数进行剪裁和变形。 ![](https://oss.showapi.com/doc/3105/70/f99e3706403645d5ae70f9ba41f86a55.png) proxy阶段主要完成以下功能: **1.输入转发字段映射** **2.系统字段转发** **3.合成字段配置** **4.代码转换** # 1. 输入转发字段映射 整体示意图示下: ![](https://oss.showapi.com/doc/3105/70/edef44c7dbea4157843b453d3b026873.png) 假设有一个接口,它定义了这样三个参数: ![](https://oss.showapi.com/doc/3105/70/7db435a7e67f46d5bb6510cd5fe86106.png) 这个接口上线,客户端也在正常调用了,但是后端服务由于某些原因,把原来的[my_para]参数改为了[new_para]参数。这样就导至大面积的客户端请求失败,直到这个时候服务方才发现【动了不该动的东西,惹了不该惹的人】,但事已至此,如何解决呢?通常的做法是这样: 1. 服务商修改程序,重启。可以同时接受my_para和new_para参数,这样客户端的代码都不用改。 2. 客户端修改程序,重启。把原来传的my_para改为new_para,大面积重启客户端程序。 可以看到这二种方式都很痛苦。有没有更好的办法呢?有的,使用易源【输入转发字段映射】,1分钟解决。 ![](https://oss.showapi.com/doc/3105/70/f877dcb006bf4415a335a9dfbd5490c0.png) 经过易源的一个映射操作,客户端和服务方都不用做调整了,业务顺利进行。 # 2. 系统字段转发 用户提交信息到易源,易源再将信息转发至后端服务。 如果后端服务需要了解调用者的更多信息,那易源就得要转发更多信息到后端。其流程示意图示下: ![](https://oss.showapi.com/doc/3105/70/80ff50dd807e428889f5b28bdecc2045.png) 配置界面如下: ![](https://oss.showapi.com/doc/3105/70/978b7327bb2149859e134bada02e44d0.png) # 3. 合成字段配置 把多个字段变量合成一个新的字段值。其逻辑图如下: ![](https://oss.showapi.com/doc/3105/70/c362129b4c6245bab9a85e04693ea43f.png) 根据输入参数+环境变量,合成新的参数。图中的{{@变量}}是mustache语法,表明其会应用【反sql注射】操作。 ## 3.1 使用场景1 假设这么样的一个接口,传给它一个sql语句,接口执行这个sql,然后把内容返回。这个sql可能会是: ```sql select * from user where name="张三" and age=22 ``` 在完全可信的环境中,传递一个sql过来是没问题的,但绝大部份API环境我们都认为是危险的,让用户直接传一个sql语句实在是太【艺高人胆大了】,有什么办法可以优化呢? 有的,如果我们让用户只传name和age过来不就行了吗?好,现在的sql语句应该是: ```sql select * from user where name="{{my_para}}" and age={{age}} ``` my_para和age就是在req阶段定义的输入参数,my_para是String,age是Number。 我们把上面的sql语句做为一个【合成的新变量字段】,假如传入的my_para=张三 ,age=22,那么生成的sql语句将是: ```sql select * from user where name="张三" and age=22 ``` 看起来是没问题了。但里面有一个重大的安全隐患:sql注射! 因为用户输入的my_para可能会被注射,那如何解决呢,也简单,我们把变量{{my_para}}换成{{@my_para}}也就是加一个@符号,同时把变量外的双引号去掉,像下面这样: ```sql select * from user where name={{@my_para}} and age={{@age}} ``` 易源会对@符号引用的变量做sql注射的转义,因此它是安全的。由于my_para是String类型,因此 ```sql {{@my_para}} 将会生成 "张三" ``` 而age是Number类型,因此 ```sql {{@age}} 将会生成 22 ``` 对应下来,整个sql语句生成后是: ```sql select * from user where name="张三" and age=22 ``` 我们来看下图示操作: ![](https://oss.showapi.com/doc/3105/70/cf037c83505247d8875f479e518938c8.png) ## 3.2 使用场景2 通常在post提交时,使用的编码是: ```html Content-Type: application/x-www-form-urlencoded;charset=utf-8 ``` 这也是表单在post时默认的提交编码: ```html <form> <input type="text" name="my_para"> </form> ``` 但也有不少后端服务接收的不是application/x-www-form-urlencoded编码,而是json,例如: ```html Content-Type: application/json ``` 直观地讲,就是需要post一整个json串到接口,而不是key1=v&key2=v&key3=v这样的串。下面示例就是百度短链接接口的真实调用: ```bash curl -H "Content-Type:application/json" -H "Token: 你的token" -X POST "https://dwz.cn/admin/v2/create" -d '{"url":"你的长网址","TermOfValidity ":"有效期"}' ``` 可以看到post的编码是: ```html Content-Type: application/json ``` 而且post的body体为: ```json {"url":"你的长网址","TermOfValidity ":"有效期"} ``` 如果把百度的`https://dwz.cn/admin/v2/create`作为一个后端服务,我们当然可以要求客户端传输整个串`{"url":"你的长网址","TermOfValidity ":"有效期"}`到易源,易源再原封不动把它转发给百度就行,但是让客户端组织这个json串有时还是挺麻烦的,能不能让客户端只传url和TermOfValidity两个参数,然后易源把需要的json串给拼出来,再转发给百度不是更好?现在就来看看怎么做。 ###首先定义url和TermOfValidity参数 就像这个图: ![](https://oss.showapi.com/doc/3105/70/98e7d0a0cb3f48df848b48b6a3db555c.png) ###在proxy中定义合成字段 我们需要合成的串是这样 ```json {"url":"你的长网址","TermOfValidity ":"有效期"} ``` 刚才已经定义字段变量了,那现在可以做变量嵌入以生成上面的json串。 ```json {"url":{{@url}},"TermOfValidity ":{{@TermOfValidity}}} ``` 把上面这串作为合成字段的模板,如图: ![](https://oss.showapi.com/doc/3105/70/53061e75a3ef47c5b953a6ec4ba4116b.png) ###在balance中定义后端服务 如下图所示: ![](https://oss.showapi.com/doc/3105/70/edefa09a137141bf9c0814c212c92ac9.png) 这样我们就实现了从客户端输入 url和TermOfValidity字段,由易源组装json转发到百度,从而实现百度的短链接接口。 # 4. 代码转换 如果需要使用比字段映射更强的功能(比如复杂的逻辑判断),可以使用【代码转换】功能,嵌入LUA代码直接修改输入参数。本功能逻辑图如下: ![](https://oss.showapi.com/doc/3105/70/b1fcfc9d8c2d4b378884a480e1d0932f.png) 您可以使用LUA代码,对输入参数进行任意的改动调整,您需要做的是实现以下的回调函数: ```lua --如果返回非nil的字符串err_info,则流程中止,调用失败,系统对外返回备注为err_info. function( post, --post参数map query, --query参数map header, --header参数map showapi_env,--全局环境变量 node_name --后端本次使用的节点名 ) --示例用法:在post设置num字段,然后删除query中的某个字段 post.num="15874521236" query.num=nil end ``` # 4.1 post,query,header 这三个参数比较简单明了,分别指代输入参数的三个位置,您可以在代码中对它们进行增加、修改、删除字段的处理。例如: ```lua post.num="15874521236" query.num=nil --把post中的num设置一个新值,同时把query中的num字段移除。 ``` > 如果在post容器中设置了showapi_bodyString参数,则整体请求体将被替换为showapi_bodyString # 4.2 showapi_env 此输入参数是当前API主人定义的环境变量。如果有如下环境变量: ![](https://oss.showapi.com/doc/3105/70/7169b86b6fc44b7b828c03a666faaa49.png) 则在代码中可以使用: ```lua local my_ip=showapi_env.my_ip local my_port=showapi_env.my_port --业务逻辑 ``` # 4.3 node_name 在有多个后端节点的时候,易源会把选中的节点名称,传入lua回调函数中。这样代码可以根据不同的节点,进行不同的业务逻辑操作。例如下图就有node1和node2两个节点。 ![](https://oss.showapi.com/doc/3105/70/3b037d08bd944b26968ef96c3c41848d.png) 那么在lua回调时,node_name可能是`node1`和`node2`,您可以根据实际节点编写不同的代码逻辑。 # 4.4 回调函数返回 如果本回调返回nil,则流程继续; 如果返回一个字符串(比如说"业务不允许这样的输入"),则整个请求流程终止,易源将整体返回类似如下信息: ```json { "showapi_res_error": "lua code transform err: 业务不允许这样的输入", "showapi_res_id": "1ba8f18564e44ceab46f062fffb4e2f2", "showapi_res_code": -1005, "showapi_res_body": { } } ``` # 4.5 使用实例介绍 比如我们要连接手机归属地查询接口,有两个API源(比如阿里市场上两个服务商提供的【手机归属地】接口),它们的输入参数分别是num和number,而我们的接口定义的输入参数是phone,如图所示: ![](https://oss.showapi.com/doc/3105/70/c37c9865bfec4a368aed4b55cb7eca4a.png) 那我们可以在易源的proxy阶段编写代码转换,根据结点名称进行不同的操作,如下图流程: ![](https://oss.showapi.com/doc/3105/70/c7cb65e314f4450abff0c77836fe6b69.png) 此lua代码像下面的样子: ```lua function( post, --post参数map query, --query参数map header, --header参数map showapi_env,--全局环境变量 node_name --后端本次使用的节点名 ) if node_name=="node1" then --对node1的映射 post.num=post.phone elseif node_name=="node2" then --对node2的映射 post.number=post.phone end post.phone=nil --移除原先的phone字段 end ``` > 上述代码是假设传入的方式是post。如果是get,则代码体里需要操作query。