Virtuesoft.Framework.Gateaway 一个超级简单的webapi接口框架
Virtuesoft.Framework.Gateaway api接口框架
起源
公司的系统需要做一个开放平台的接口对外提供一些服务.之前都用webapi 或者mvc来实现.但是用久了之后发现各种引用的包,各种插件其实都用不上.配置也麻烦.(首先申明我是一个非常懒,非常懒,懒到出奇的人,懒到多一个代码,多一个符号都不想打的人.)功能要求很很简单,就是响应http请求然后处理数据返回信息,而且我还不想写文档(写api文档太多拷贝复制,而且更新了还要…所以干脆写到代码,让前端去累!),仅此而已,所以干脆自己造个轮子,顺便可以了解和提升一下代码质量.(闲得蛋疼)所以就花了几个小时干了这么个玩意儿,再写个博客记录一下(差不多最后一次写博客是2012年).
最简单的使用
- 新建一个空的asp.net core web 项目,记住,什么都没有的.
- 导入nuget包 Virtuesoft.Framework.Gateaway ;
- 修改 Startup 在ConfigureServices中添加 services.AddGateaways() ,子Configure 中添加 app.UseGateaway();
大概就是下面这个样子
public void ConfigureServices(IServiceCollection services)
{
services.AddGateaways();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseGateaway();
}
不要考虑了,就这些,没有多的代码.说了我讨厌那么多冗余的代码.而且不想写文档.
- 然后,就没有然后了.当然我个人习惯不喜欢直接用iis express启动,所以我修改了一下Program 用控制台方式启动;
上代码吧,自己看.(我这个代码是用的控制台程序,没有使用asp.net core 项目)
public static void Main(string[] args)
{
WebHostBuilder webHost = new WebHostBuilder();
webHost.UseStartup<Startup>()
.UseDefaultServiceProvider(config => { })
.UseUrls("http://10.0.0.90:1111")
.UseKestrel()
.Build()
.Run();
}
然后启动postman
post方式.form提交一个参数: method=api.doc
当然用json提交也可以,就是不支持get,不要问为什么,反正不支持.
这个是结果:
框架带了一个默认的接口文件,就是文档.可以返回当前项目中所有的接口信息和描述.这个就是想累死那些做前端,让他们直接ajax过去拿数据,然后生成文档界面.这样只要我更新代码,前端界面就更新了.由于文档页面可能出现在不同的网站上,而且界面也不同,所以就不做到api的接口里面了.个人觉得这样的方法,程序员最偷懒.
这里默认了3个api,
api.catalog : 接口文档目录,只返回接口名称和描述
api.doc : 显示所有接口文档
api.query : 查询单个接口详细内容
参数类型,返回值等都有,自己去看,我也懒得和前端沟通了.
写一个自己的接口
新建一个类 Member 继承GateawayBase
重写一下Controller 属性 (这个是导航属性)
算了,不想写中文了,直接上代码
public class Member:GateawayBase
{
public override string Controller => "member";
public async Task<int> Online()
{
return await Task.FromResult(0);
}
}
再打开postman 修改参数 method=member.online
这次我用json提交,一定要记得类型是json
返回值的格式可以自己定义,后面再说.返回一个0 默认是 d 参数.
再写个方法,返回复杂类型的数据
先新增一个user类
public class User {
public string name { get; set; }
public string sex { get; set; }
public string phone { get; set; }
}
再添加一个paged方法,用于获取一个用户的数组
public User[] Paged() {
return new User[] {
new User(){ name="好",phone="1111111",sex="男"},
new User(){ name="多",phone="2222222",sex="女" },
new User(){ name="吊",phone="3333333",sex="男"},
new User(){ name="毛",phone="4444444",sex="女"},
new User(){ name="啊",phone="5555555",sex="男"},
};
}
postman 一下看结果
如果没有其他特殊的要求,就可以开始尽情的写接口了.
我们看看接口文档返回的是啥:
为什么没有描述?
为什么没有默认值?
为什么…
还没到地方.
进阶一步,验证必要参数.
对于api接口来说,需要约束公共参数,这些都是必填的.比如商户平台,需要传递公共参数为商户的编号,签名方式,随机字串,时间戳等等.
当然,这个是很简单的.
修改 Startup 文件,
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseGateaway(option=> {
option.OnVerifyPrameters = (forms,httpcontent) => {
if(!forms.ContainsKey("merchid"))
return (false, "缺少参数:merchid");
if (!forms.ContainsKey("timestamp"))
return (false, "缺少参数:timestamp");
if (!forms.ContainsKey("noncestr"))
return (false, "缺少参数:noncestr");
if (!forms.ContainsKey("signtype"))
return (false, "缺少参数:signtype");
if (!forms.ContainsKey("sign"))
return (false, "缺少参数:sign");
return (true,"ok");
};
});
}
如果你问 return (true,“ok”); 这是什么写法的话,那去看看 System.ValueTuple 这个有详细说明,只是为了返回多个值.都说了我懒,不想为了几个参数就去新建一个类.
然后我们post一下数据过去.
post->
{"method":"api.doc"}
return->
{"s":false,"c":500,"m":"缺少参数:merchid","d":null}
正常返回错误信息.
我们吧参数写全
post->
{"method":"member.paged",
"merchid":"20191259856854",
"timestamp":"12345623413",
"noncestr":"daseedgerydfhtrjert",
"signtype":"md5",
"sign":"299A1196F95E628D98ADE35CCA04BE77"}
result->
{
"s": true,
"c": 200,
"m": "",
"d": [
{
"name": "好",
"sex": "男",
"phone": "1111111"
},
{
"name": "多",
"sex": "女",
"phone": "2222222"
},
{
"name": "吊",
"sex": "男",
"phone": "3333333"
},
{
"name": "毛",
"sex": "女",
"phone": "4444444"
},
{
"name": "啊",
"sex": "男",
"phone": "5555555"
}
]
}
正常返回.
进阶第二部验证签名
至于你想怎么去验证我不知道,我就用支付宝的算法吧.
signtype,sign 和值为空的参数不参与签名
参数按键名排序->拼接为url格式->转换大写->md5.
当然这里少了一步拼接个key,这个是和调用者协商的**.当然你可以rsa,des,aes什么的乱七八糟一堆.
我见过一个接口,他把常用的加密方式全部用了一遍,不管解密麻烦,还多重加密一下(什么银行就不点名了).
服务器端验证签名:
修改 Startup 文件,
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseGateaway(option=> {
option.OnVerifyPrameters = (forms,httpcontent) => {
if(!forms.ContainsKey("merchid"))
return (false, "缺少参数:merchid");
if (!forms.ContainsKey("timestamp"))
return (false, "缺少参数:timestamp");
if (!forms.ContainsKey("noncestr"))
return (false, "缺少参数:noncestr");
if (!forms.ContainsKey("signtype"))
return (false, "缺少参数:signtype");
if (!forms.ContainsKey("timestamp"))
return (false, "缺少参数:timestamp");
return (true,"ok");
};
option.OnVerifySign = (forms, httpcontent) =>
{
var dataArry= forms.Where(t => t.Key != "signtype")
.Where(t => t.Key != "sign")
.Where(t => t.Value.IsNullOrEmpty())
.OrderBy(t => t.Key)
.Select(t=>$"{t.Key}={t.Value}")
.ToArray();
var sign = string.Join("&", dataArry)
.ToUpper()
.Md5Encrypt();
return sign== forms["sign"];
};
});
}
继续测试
post->
{"method":"member.paged",
"merchid":"20191259856854",
"timestamp":"12345623413",
"noncestr":"daseedgerydfhtrjert",
"signtype":"md5",
"sign":"299A1196F95E628D98ADE35CCA04BE77"}
result->
{
"s": false,
"c": 500,
"m": "签名错误",
"d": null
}
当然你还可以验证其他的或者直接修改掉验证方式,甚至做个登录保存user的东西都没问题.
还有,访问数据库什么的和asp.net core一样,配置,接口也支持DI注入什么的.哎就不多说了.
所有的参数设置都I在 option.On*** 中,比如修改返回值的格式.在响应请求之前写入日志,响应之后写入日志,ip限制等都在里面.
我发现今天写了很多字,有点手累.
如果有什么好的建议可以留言,最后截图一个:
一个项目除了基础文件,几乎没有多余的任何文件,主要是真的懒.
后续更新
处理其他平台的回调函数
扩展修改路由方式
数据库操作案例