java 单机接口限流处理方案
390
2022-11-06
本文目录一览:
Api接口就好比一个媒介工具,比如买东西的时候我们要计算价格,可以用算盘、计算器、手机或者电脑进行计算得出结果。接口与其类似,当你需要用到这个功能时就可以调用。
Api接口可以应用于pc端、app、软件等,除了接口一般会有Api接口文档说明来帮助开发者使用。
下面来分享一下免费的api接口以及文档说明:
1. 邮编查询:
接口地址:
返回格式:json/xml
请求方式:http get/post
请求示例:;key=申请的KEY
接口备注:通过邮编查询对应的地名
请求参数说明:
名称 类型 必填 说明
postcode 是 string 邮编,如:215001
key 是 string 应用APPKEY(应用详细页查询)
page 否 int 页数,默认1
pagesize 否 int 每页返回,默认:20,最大不超过50
dtype 否 string 返回数据的格式,xml或json,默认json
返回参数说明:
名称 类型 说明
error_code int 返回码
reason string 返回说明
JSON返回示例:
{
"reason": "successed",
"result": {
"list": [
{
"PostNumber": "215001",
"Province": "江苏省",
"City": "苏州市",
"District": "平江区",
"Address": "廖家巷新光里"
},
{
"PostNumber": "215001",
"Province": "江苏省",
"City": "苏州市",
"District": "平江区",
"Address": "龙兴桥顺德里"
}
],
"totalcount": 352,
"totalpage": 176,
"currentpage": 1,
"pagesize": "2"
},
"error_code": 0
}
2. 手机号码归属地:
接口地址:
返回格式:json/xml
请求方式:get
请求示例:;key=您申请的KEY
请求参数说明:
名称 类型 必填 说明
phone 是 int 需要查询的手机号码或手机号码前7位
key 是 string 应用APPKEY(应用详细页查询)
dtype 否 string 返回数据的格式,xml或json,默认json
返回参数说明:
名称 类型 说明
error_code int 返回码
reason string 返回说明
result string 返回结果集
province string 省份
city string 城市,(北京、上海、重庆、天津直辖市可能为空)
areacode string 区号,(部分记录可能为空)
zip string 邮编,(部分记录可能为空)
company string 运营商
JSON返回示例:
{
"resultcode":"200",
"reason":"Return Successd!",
"result":{
"province":"浙江",
"city":"杭州",
"areacode":"0571",
"zip":"310000",
"company":"中国移动",
"card":""
}
}
XML返回示例:
?xml version="1.0" encoding="utf-8" ?
- root
resultcode200/resultcode
reasonReturn Successd!/reason
- result
province浙江/province
city杭州/city
areacode0571/areacode
zip310000/zip
company中国移动/company
card/card
/result
/root
3. 影视影讯检索:
接口地址:
返回格式:json/xml
请求方式:http get/post
请求事例;q=%E5%BA%B7%E7%86%99%E7%8E%8B%E6%9C%9D
接口备注:电影:q=心花路放;电视剧:q=继承者们;动漫:q=柯南
请求参数说明:
名称 类型 必填 说明
key 是 string 应用APPKEY(应用详细页查询)
dtype 否 string 返回数据的格式,xml或json,默认json
q 是 string 影视搜索名称
返回参数说明:
名称 类型 说明
error_code int 返回码
reason string 返回说明
JSON返回示例:
{
"reason": "查询成功",
"result": {
"title": "闪电侠第一季",
"tag": "科幻 / 动作",
"act": "格兰特·古斯汀 埃涅·赫德森 汤姆·卡瓦纳夫",
"year": "2014",
"rating": null,
"area": "美国",
"dir": "大卫·努特尔",
"desc": "《闪电侠》精彩看点:二次元超级英雄再登电视荧屏,《闪电侠》无缝对接《绿箭侠》闪耀登场。《闪电侠》剧情梗概:《闪电侠》的漫画连载开始于1940年,讲述了一名拥有超级速度的学生的故事。50年代起,这个角色则被重新诠释,成为了巴里·艾伦,一名为警署工作的科学家,使用他的超级速度来对抗超级反派们。",
"cover": "",
"vdo_status": "play",
"playlinks": {
"youku": "",
"qq": "",
"leshi": "",
"pptv": "",
"sohu": ""
},
"video_rec": [
{
"detail_url": "",
"cover": "",
"title": "神盾局特工 第2季"
},
{
"detail_url": "",
"cover": "",
"title": "遗失的世界"
},
{
"detail_url": "",
"cover": "",
"title": "浩劫余生 第一季"
},
{
"detail_url": "",
"cover": "",
"title": "新绿野仙踪之铁皮人"
},
{
"detail_url": "",
"cover": "",
"title": "陨落星辰第三季"
}
],
"act_s": [
{
"name": "格兰特·古斯汀",
"url": "",
"image": ""
},
{
"name": "埃涅·赫德森",
"url": "",
"image": ""
},
{
"name": "汤姆·卡瓦纳夫",
"url": "",
"image": ""
}
]
},
"error_code": 0
}
4. 商品比价查询:
API调用地址:
申请appkeyKey=搜索关键词Class=分类IDBrand=品牌IDSite=商城IDPriceMin=最低价PriceMax=最高价PageNum=页号PageSize=每页商品数OrderBy=排序方式ZiYing=是否自营ExtraParameter=扩展参数
调用示例
;Key=iphoneClass=0Brand=0Site=0PriceMin=0PriceMax=0PageNum=1PageSize=30OrderBy=scoreZiYing=falseExtraParameter=0
返回结果示例(以iphone为例,显示前2条商品信息):
{"State":1000,"SearchItemsCount":101520,"SearchCount":5109,"ClassList":"57|1074|手机,893|29964|iPhone 配件,892|19512|手机保护套,910|11169|苹果配件, 890|8766|手机贴膜 ,894|6201|其它配件,900|3189|移动电源,889|2067|手机充电器,898|1923|电池/充电器,101|1518|耳机,888|1290|手机电池, 100|1074|蓝牙耳机","BrandList":"155|47184|苹果,0|40476|,634|2166|洛克,6|1134|三星,622|1023|倍思,261|564|品胜,652|558|SGP, 639|537|ESR,623|474|邦克仕,10|423|飞利浦,604|330|摩米士,664|291|优胜仕","SiteList":"1|66732|京东商城,4|8478|亚马逊,3|7917| 当当,13|4821|1号店,6|4605|苏宁易购,8|4149|国美在线,11|3882|易迅网,9|360|新蛋网,161|168|飞牛网,185|147|顺电网,124|123|高鸿商城, 123|69|华强北","SearchResultList":[{"spname":"苹果(Apple)iPhone 6 (A1586) 16GB 金色 移动联通电信4G手机", "sppic":"", "spurl":"","spprice":"5188.00","className":"手机","brandName":"苹果","siteName":"京东商城", "commentUrl":"","commentCount":"8773", "TitleHighLighter":"苹果(Apple)iPhone 6 (A1586) 16GB 金色 移动联通电信4G手机","ziying":"1","siteid":"1","id":"98084930"}, {"spname":"苹果(Apple)iPhone 6 Plus (A1524) 16GB 金色 移动联通电信4G手机", "sppic":"", "spurl":"","spprice":"5988.00","className":"手机","brandName":"苹果","siteName":"京东商城", "commentUrl":"","commentCount":"10288", "TitleHighLighter":"苹果(Apple)iPhone 6 Plus (A1524) 16GB 金色 移动联通电信4G手机","ziying":"1","siteid":"1","id":"98084932"}]}
一些刚开始写接口文档的服务端同学,很容易按着代码的思路去编写接口文档,这让客户端同学或者是服务对接方技术人员经常吐槽,看不懂接口文档。这篇文章提供一个常规接口文档的编写方法,给大家参考。
一、请求参数
1. 请求方法
GET
用于获取数据
POST
用于更新数据,可与PUT互换,语义上PUT支持幂等
PUT
用于新增数据,可与POST互换,语义上PUT支持幂等
DELETE
用于删除数据
其他
其他的请求方法在一般的接口中很少使用。如:PATCH HEAD OPTIONS
2. URL
url表示了接口的请求路径。路径中可以包含参数,称为地址参数,如**/user/{id}**,其中id作为一个参数。
3. HTTP Header
HTTP Header用于此次请求的基础信息,在接口文档中以K-V方式展示,其中Content-Type则是一个非常必要的header,它描述的请求体的数据类型。
常用的content-type:
application/x-www-form-urlencoded
请求参数使用“”符号连接。
application/json
内容为json格式
application/xml
内容为xml格式
multipart/form-data
内容为多个数据组成,有分隔符隔开
4. HTTP Body
描述http body,依赖于body中具体的数据类型。如果body中的数据是对象类型。则需要描述对象中字段的名称、类型、长度、不能为空、默认值、说明。以表格的方式来表达最好。
示例:
二、响应参数
1. 响应 HTTP Body
响应body同请求body一样,需要描述请清除数据的类型。
另外,如果服务会根据不同的http status code 返回不同的数据结构, 也需要针对不同的http status code对内容进行描述。
三、接口说明
说明接口的应用场景,特别的注意点,比如,接口是否幂等、处理是同步方式还是异步方式等。
四、示例
上个示例(重点都用红笔圈出来,记牢了):
学习了百度云盘文件API接口的使用;初步是想做一个在线android应用,应用中的文档是存放在百度云盘的。
主要是分一下几个步骤:
1.注册百度账号
2.登录百度开发者中心
3.创建移动应用,获取对应的(API Key Secret Key)
4.开通pcs API权限
5.获取ACCESS_token(认证编码)
6.开发应用
注意:
开通移动应用,获取key
获取token的时候我使用的安卓获取的方式
通过我写对应api的例子我发现,其实就两种情况:一种是get方式提交数据,另外一种是post方式提交数据
1.get方式提交数据,我们用获取云盘的信息为例:
获取云盘信息前我们要知道,我们要准备好什么数据:
请求参数:
url: 标明我们要访问的网址路径 值固定问""
method:标明我们是请求云盘信息 值固定为"info"
acceess_token:准入标识 值是我们自己申请的
接收返回参数:
quota:云盘总容量
used:云盘使用容量
request_id:该请求的表示,没啥用
返回的一个json串如下格式:{"quota":123794882560, "used":83573494688,"request_id":2853739529}
我在做的时候你使用Gson工具将json串转换到对应的entity类中了 代码如下:
[html] /**
* @param URLConnection conn通过get方式获取StringBuffer
* @return
*/
private StringBuffer getJsonString(URLConnection conn) {
InputStreamReader isr = null;
BufferedReader br = null;
StringBuffer sb = null;
try {
isr = new InputStreamReader(conn.getInputStream(),"gb2312");
br = new BufferedReader(isr);
String line = null;
sb = new StringBuffer();
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append("\r\n");
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if(isr!=null)
isr.close();
} catch (IOException e) {
System.out.println("流关闭是异常");
e.printStackTrace();
}
}
return sb;
}
/**
* @return
* @throws Exception
* 获取云空间的信息
*/
public CloudInfo getCloudInfo() throws Exception {
URL u = new URL("?method=infoaccess_token=你申请的token的值";
URLConnection conn = u.openConnection();// 打开网页链接
// 获取用户云盘信息
String cloudJson = this.getJsonString(conn)。toString();
// 解析成对象 下面有这个实体对象的类
Gson gson = new Gson();
CloudInfo cloudInfo = gson.fromJson(cloudJson, CloudInfo.class);
System.out.println("云盘信息:"+cloudInfo);
return cloudInfo;
}
/**
* @param URLConnection conn通过get方式获取StringBuffer
* @return
*/
private StringBuffer getJsonString(URLConnection conn) {
InputStreamReader isr = null;
BufferedReader br = null;
StringBuffer sb = null;
try {
isr = new InputStreamReader(conn.getInputStream(),"gb2312");
br = new BufferedReader(isr);
String line = null;
sb = new StringBuffer();
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append("\r\n");
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if(isr!=null)
isr.close();
} catch (IOException e) {
System.out.println("流关闭是异常");
e.printStackTrace();
}
}
return sb;
}
/**
* @return
* @throws Exception
* 获取云空间的信息
*/
public CloudInfo getCloudInfo() throws Exception {
URL u = new URL("?method=infoaccess_token=你申请的token的值";
URLConnection conn = u.openConnection();// 打开网页链接
// 获取用户云盘信息
String cloudJson = this.getJsonString(conn)。toString();
// 解析成对象 下面有这个实体对象的类
Gson gson = new Gson();
CloudInfo cloudInfo = gson.fromJson(cloudJson, CloudInfo.class);
System.out.println("云盘信息:"+cloudInfo);
return cloudInfo;
}
[html] package com.entity;
import java.lang.reflect.Type;
/**
* @author ydcun 获取云空间的信息 例如:
* {"quota":123794882560, 空间配额,单位为字节
* "used":83573494688, 已使用空间大小 单位为字节。
* "request_id":2853739529}
*/
public class CloudInfo{
private Double quota;
private Double used;
private Double request_id;
/**
* @return the quota 空间配额,单位为字节
*/
public Double getQuota() {
return quota;
}
/**
* @param quota the quota to set 空间配额,单位为字节
*/
public void setQuota(Double quota) {
this.quota = quota;
}
/**
* @return the used 已使用空间大小 单位为字节
*/
public Double getused() {
return used;
}
/**
* @param used the used to set 已使用空间大小 单位为字节
*/
public void setused(Double used) {
this.used = used;
}
/**
* @return the request_id
*/
public Double getRequest_id() {
return request_id;
}
/**
* @param request_id the request_id to set
*/
public void setRequest_id(Double request_id) {
this.request_id = request_id;
}
@Override
public String toString() {
return new StringBuffer()。append("空间容量:")。append(this.getQuota()/1024/1024)。append("M; 已用:")。append(this.getused()/1024/1024)。append("M; ")。toString();
}
}
package com.entity;
import java.lang.reflect.Type;
/**
* @author ydcun 获取云空间的信息 例如:
* {"quota":123794882560, 空间配额,单位为字节
* "used":83573494688, 已使用空间大小 单位为字节。
* "request_id":2853739529}
*/
public class CloudInfo{
private Double quota;
private Double used;
private Double request_id;
/**
* @return the quota 空间配额,单位为字节
*/
public Double getQuota() {
return quota;
}
/**
* @param quota the quota to set 空间配额,单位为字节
*/
public void setQuota(Double quota) {
this.quota = quota;
}
/**
* @return the used 已使用空间大小 单位为字节
*/
public Double getused() {
return used;
}
/**
* @param used the used to set 已使用空间大小 单位为字节
*/
public void setused(Double used) {
this.used = used;
}
/**
* @return the request_id
*/
public Double getRequest_id() {
return request_id;
}
/**
* @param request_id the request_id to set
*/
public void setRequest_id(Double request_id) {
this.request_id = request_id;
}
@Override
public String toString() {
return new StringBuffer()。append("空间容量:")。append(this.getQuota()/1024/1024)。append("M; 已用:")。append(this.getused()/1024/1024)。append("M; ")。toString();
}
}
2.通过post方式提交 我用上传单个文件为例子:
同样我们也先了解下上传文件要参数设置:
请求参数:
url: 标明我们要访问的网址路径 值固定问""
method:标明我们是请求云盘信息 值固定为"upload"
acceess_token:准入标识 值是我们自己申请的
path:是我们要上传到云盘的那个路径下 如/apps/myBaiduCloud/ myBaiduCloud是我们的应用名称(当你获取koten后就会自动生成以你应用名称为名的文件夹)
file:这个就是我们要上传的文件了(要求用post方式上传)
ondup:可选参数,标识当有重名的文件的时候处理方式具体见api
接收返回参数:
返回的也是json串,
path:为我们上传的文件保存的全路径
size:文件的大小有多少字节
ctime/mtime:文件的创建修改时间
其他参数介绍点小标题去api中查看
{
"path" : "/apps/album/README.md"
"size" : 372121,
"ctime" : 1234567890,
"mtime" : 1234567890,
"md5" : "cb123afcc12453543ef",
"fs_id" : 12345,
"request_id":4043312669
}
我在做的时候也是将其封装到实体类中了,这里和上面一样不详述,我们重点看下提交文件是怎么提交的代码如下:
[java] /**
* @param path 云盘存放路径
* @param name 要上传的文件
* @return
* @throws Exception
*/
public FileBase uploadFile(String path,File file) throws Exception{
//模拟文件
String fileName="README.md";
file = new File(fileName);
path="%2fapps%2fmybaidu%2f"; // 我用的是url编码过源码为:- "/apps/mybaidu/
/"
//将需要url传值的参数和url组装起来
String u =""+path+file.getName()+"method=uploadaccess_token=你自己申请的token值";
PostMethod filePost = new PostMethod(u);
//post提交的参数
Part[] parts = {new FilePart(fileName,file)};
//设置多媒体参数,作用类似form表单中的enctype="multipart/form-data"
filePost.setRequestEntity(new MultipartRequestEntity(parts, filePost.getParams()));
HttpClient clients = new HttpClient();
//响应代码
int status = clients.executeMethod(filePost);
System.out.println("成功上传"+path+fileName);
BufferedReader buReader = new BufferedReader(new InputStreamReader(filePost.getResponseBodyAsStream(),"utf-8"));
StringBuffer sb = new StringBuffer();
String line;
while((line=buReader.readLine())!=null){
sb.append(line);
}
buReader.close();
// 解析成对象
Gson gson = new Gson();
FileBase cloudInfo = gson.fromJson(sb.toString(), FileBase.class);
return cloudInfo;
}
/**
* @param path 云盘存放路径
* @param name 要上传的文件
* @return
* @throws Exception
*/
public FileBase uploadFile(String path,File file) throws Exception{
//模拟文件
String fileName="README.md";
file = new File(fileName);
path="%2fapps%2fmybaidu%2f"; // 我用的是url编码过源码为:- "/apps/mybaidu/
/"
//将需要url传值的参数和url组装起来
String u =""+path+file.getName()+"method=uploadaccess_token=你自己申请的token值";
PostMethod filePost = new PostMethod(u);
//post提交的参数
Part[] parts = {new FilePart(fileName,file)};
//设置多媒体参数,作用类似form表单中的enctype="multipart/form-data"
filePost.setRequestEntity(new MultipartRequestEntity(parts, filePost.getParams()));
HttpClient clients = new HttpClient();
//响应代码
int status = clients.executeMethod(filePost);
System.out.println("成功上传"+path+fileName);
BufferedReader buReader = new BufferedReader(new InputStreamReader(filePost.getResponseBodyAsStream(),"utf-8"));
StringBuffer sb = new StringBuffer();
String line;
while((line=buReader.readLine())!=null){
sb.append(line);
}
buReader.close();
// 解析成对象
Gson gson = new Gson();
FileBase cloudInfo = gson.fromJson(sb.toString(), FileBase.class);
return cloudInfo;
}
上面代码成功后我们就会在/apps/mybaidu/目录下找到README.md文件
commons-codec-1.3.jar
commons-
commons-logging.jar
gson-2.2.1.jar
jsoup-1.6.3.jar
首先API全称(Application Programming Interface,应用程序接口)是一些预先定义的函数,或指软件系统不同组成部分衔接的约定。目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问原码,或理解内部工作机制的细节。
API 定义
对于很多产品小白或求职者而言,API接口是一个产品和研发领域的专业术语,大家可能在文章或者PRD中都已经有接触过API接口的概念。
实际上,接口的应用已经非常广泛和成熟,这个概念主要活跃在公司内部的各系统之间的衔接和对接以及公司间合作的场景。如果你可以认真看完这篇文章,我相信你们对API接口的认识会更深入,甚至超过90%的小白和求职者。
本文目录:
游戏APIAPI接口是什么?
为什么我们需要游戏APIAPI接口?
游戏APIAPI接口的核心
我们来以一个常见的数学公式理解API,比如y=x+2,当x=2的时候,y=4,对么?
那此时,我们把y=x+2称为接口,x=2称为参数,y=4称为返回结果,那这个接口的功能就是能把我们输入的数加上2(注意:这里你可以发现接口自身是带有逻辑的)。
类比地,我们来理解一个常见的场景,比如现在有一个可以把经纬度转化为城市的接口,那当我输入经度是55°,纬度是88°的时候,接口通过自己的逻辑运算,返回结果告诉我:杭州市。
这样你就可以清晰地了解百度百科的官方解释了,接口就是预先定义的函数逻辑,他是供其他系统请求,然后返回结果的一个东西。
背景:我们的业务系统涉及多方多面,如果要一个公司或者一个系统把所有业务都做完,那未免工作量太大了吧?并且如果其他系统或公司有更好的运算逻辑,那我们在设计功能的时候可以考虑利用接口进行开发。
核心需求:利用现有接口可以降低开发成本,缩短开发成本。
举个例子:比如我是做游戏的APP,现在我需要在我的页面上展现游戏的功能,对于我司而言,新做开发能未免成本过太过于高,那我们可以在NGAPI接口商开放平台提供的API进行接入,这样的话我们只需要申请API接口开户,部署调用 NGAPI接口 API,这样就可以快速在我们页面上线丰富的游戏平台了。
对于小白而言,初看API文档可能是一头雾水的——从哪里看,怎么看,看什么是摆在面前的问题。
其实对于产品经理而言,我们应该更关注这个公司可以提供什么样的API接口服务,比如我知道高德可以提供地图API,规划路线的API,这样的话在我们设计功能和工作中就可以想到调用他们的服务或者参考。
所以产品小白们看不懂也不用过于担心,未来工作中你也会更深入了解清楚,因为看懂并不复杂,以下是API接口的核心点,所有的说明文档离不开这5个核心点。
以下说明均以微信开放平台为例说明,文末有各开放平台的地址,大家有空可以去学习。好了,事不宜迟,现在我们来建立一个场景。
我们现在有一个APP,需要用户在购买的时候调起微信支付的API,完成购买。请各位自动进入这个场景,把自己当作一位产品经理。
1. 接口地址
现在Now,用户点击付款,我们需要告诉微信,我们要调起你们的收银台啦!但,去哪里告诉呢?这就需要接口地址了,也就相当于向微信的这条链接传输指定的数据。
一个链接地址不是我们理解的一个页面,你可以理解是一个电话号码,小白们要改变这个观念。
此时我们可以看到接口文档告诉我们链接是如下这条,那我们现在已经拨通微信的电话了。
2. 请求参数(报文)
我们现在需要告诉微信,你想调用收银台对吧。那我们需要写下来,此时生成的叫做报文,也就是你想告诉这个接口的内容是什么?相当于前文函数的输入x=2。
一般来说,报文的格式和内容都是按接口文档规定的。如下文就是微信开放平台对调起收银台的报文要求。
我们先来看前2个参数,你现在跟微信在对话,是不是应该先告诉微信,你是谁?这里微信的文档告诉你应该要用应用ID+商户号来确定你的身份,什么意思呢?
比如你是A商户,下面有a,b,c三个APP,所以微信要知道你是哪个商家,下面的哪个APP要用收银台。这是非常重要的,微信后面要把收到的钱打到对应的账户以及统计数据等。
那我们就在报文里面写下这两句话:
appidwx2421b1c4370ec43b/appid(我的应用ID是wx2421…….)
mch_id10000100/mch_id(我的商户号是10000…….)
好了,现在微信知道你是谁了,那你要告诉微信,你需要微信支付帮你收多少钱对吧?这里定义了货币类型和总金额,也就是收什么货币,收多少钱。
这里你看,货币类型的必填写了否,也就是说你也可以不告诉微信支付货币类型是什么,因为他在后面备注了默认是人民币。
好的,那我们写下两段报文
free_typeCNY/ free_type (我要收人民币)
total_fee1/total_fee(我要收1元)
好了,现在微信知道你是谁,也知道要收多少钱了,那接下来微信支付要把收钱结果告诉你呀,因为你得知道用户是成功支付了才能继续发货,服务啊等等的。所以这里我们用到通知地址,就是告诉微信,等下完事了他去哪里告诉你支付结果。那我们把地址写好:
notify_url;/notify_url
3. 返回结果
刚刚微信支付已经去收款了,现在他要在我们留下的通知地址中,告诉我们结果了。结果无非是两种:成功收款?收款不成功?
(1)成功
很顺利,现在用户成功付钱了,并且微信也把成功的消息告诉我们了,并且他还把用户支付的一些信息也告诉我们。
那这里就是微信支付成功收款后告诉我们的信息。
应用APPID,商户号:告诉你我成功扣款的是哪家商户的哪个APPID的交易。
业务结果:成功或失败
(2)失败
在产品设计的时候,我们往往很关注失败的情况,当收款失败的时候,微信同时会告诉你失败的原因,如下图很好理解,失败的原因有很多很多种,我们在设计的时候往往要分析每种失败的原因,为每个失败的原因设计页面和用户提示,以确保用户能理解。
以上就是API接口基本运作模式的理解,下面我将继续更新API接口的一些更为深入和细节的关键元素,如请求方式/签名/加解密等等。
API接口,类似 ;mch_id=123 ,这个请求我以商户mch_id=123的身份给订单号为order_id=123退款,如果服务器不辩别请求发起者的身份直接做相应的操作,那是及其危险的。
一般的,在PC端,我们是通过加密的cookie来做会员的辨识和维持会话的;但是cookie是属于浏览器的本地存储功能。APP端不能用,所以我们得通过token参数来辨识会员;而这个token该如何处理呢?
延伸开来,接口的安全性主要围绕Token、Timestamp和Sign三个机制展开设计,保证接口的数据不会被篡改和重复调用。
一般来说,在前端对数据做加密或者前面,是不现实的。前后端使用HTTP协议进行交互的时候,由于HTTP报文为明文,所以通常情况下对于比较敏感的信息可以通过在前端加密,然后在后端解密实现"混淆"的效果,避免在传输过程中敏感信息的泄露(如,密码,证件信息等)。不过前端加密只能保证传输过程中信息是‘混淆’过的,对于高手来说,打个debugger,照样可以获取到数据,并不安全,所谓的前端加密只是稍微增加了攻击者的成本,并不能保证真正的安全。即使你说在前端做了RSA公钥加密,也很有可能被高手获取到公钥,并使用该公钥加密数据后发给服务端,所以务必认为前端的数据是不可靠的,服务端要加以辩别。敏感信息建议上https。
所以一般建议上https,敏感信息md5混淆,前端不传输金额字段,而是传递商品id,后端取商品id对应的金额,将金额等参数加签名发送到支付系统。金额可以是明文的。
token授权机制 :用户使用用户名密码登录后,后台给客户端返回一个token(通常是UUID),并将Token-UserId键值对存储在redis中,以后客户端每次请求带上token,服务端获取到对应的UserId进行操作。如果Token不存在,说明请求无效。
弊端 :token可以被抓包获取,无法预防MITM中间人攻击
用户每次请求都带上当前时间的时间戳timestamp,服务器收到请求后对比时间差,超过一定时长(如5分钟),则认为请求失效。时间戳超时机制是防御DOS攻击的有效手段。
将token,timestamp等其他参数以字典序排序,再加上一个客户端私密的唯一id(这种一般做在服务端,前端无法安全保存这个id)或使用私钥签名,将前面的字符串做MD5等加密,作为sign参数传递给服务端。
地球上最重要的加密算法:非对称加密的RSA算法。公钥加密的数据,可以用私钥解密;私钥签名(加密)的数据,可以用公钥验签。
RSA原理是对极大整数做因数分解,以下摘自维基百科。
暂时比较忙没时间,将于7月29日晚更新。
来更新啦。
微信支付安全规范,可以查看官方文档
第1点中,其签名算法最重要的一步,是在最后拼接了商户私密的API密钥,然后通过md5生成签名,这时即使金额是明文也是安全的,如果有人获取并修改了金额,但是签名字段他是无法伪造的,因为他无法知道商户的API密钥。当然,除了微信支付的拼接API生成签名的方法,我们也可以通过java自带的security包进行私钥签名。其中nonce随机字符串,微信支付应该做了校验,可以防止重放攻击,保证一次请求有效,如果nonce在微信支付那边已经存在,说明该请求已执行过,拒绝执行该请求。
阮一峰老师的博客-RSA算法原理:
维基百科:
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~