Appearance
API
概述
API允许外部系统以HTTP
协议的形式和应用交互,每一个API拥有一个唯一的访问路径,在HTTP
请求到达时,执行配置的自动化
程序或者脚本
函数,将执行结果按照配置的格式返回给调用端。
ℹ️ 重要信息
API执行的自动化程序必须是不包含交互式步骤的
API调用时header无法传递名字中包含
_
需要在nginx上设置
underscores_in_headers on;
,文档可参考
访问路径
shell
https://$host/web0/api/${appId}/${path}
${path}
是配置的路径${appId}
是应用ID
前处理
如果设置了 在调用前执行
,则会在调用脚本或者自动化之前执行设置的前处理脚本
。通过设置前处理可以很方便的实现类似鉴权和审计的功能。 如果前处理调用脚本抛出异常,则API调用会返回错误。如果前处理脚本有返回值,则API会直接返回此返回值。
前处理脚本接受一个参数,参数的类型APIContext
示例
api调用前鉴权,检查token是否有效,如果无效则返回token过期错误
1.示例api(test)配置好调用前处理调用脚本和脚本函数 如:preHandle
2.调用前脚本函数如下
javascript
export function preHandle(ctx) {
console.log('preHandle',ctx);
var token=ctx.query['token'];
console.log('token',token);
if(token==null){
informat.app.abort('token cannot be null');
return;
}
var account=informat.system.getAccountByToken(token);
if(account==null){
informat.app.abort('token expired');
return;
}
ctx.request.setAttribute('account',account);//后续脚本可以通过ctx.request.getAttribute('account')获取访问用户信息
}
3.调用API
没有传递token的情况
shell
$ curl https://next.informat.cn/web0/api/croe0zft168y3/test
json
{
"code":270001,
"message":"token cannot be null",
"requestId":"v35glpx5vojke"
}
token过期的情况
shell
$ curl https://next.informat.cn/web0/api/croe0zft168y3/test?token=796bfe7f246d4ee18c3d1133672e9991
json
{ "code":270001,
"message":"token expired",
"requestId":"prkk3dqzgrv34"
}
后处理
如果设置了 在调用后执行
,则会在调用脚本或者自动化之后执行设置的后处理脚本
。通过设置后处理可以很方便的实现审计等功能。 如果后处理设置的脚本抛出异常,则API调用会返回错误。如果后处理脚本或者自动化有返回值,则API会直接返回此返回值。
前处理自动化或者脚本接受两个参数,参数1是客户端传递的请求信息,类型为APIContext
。参数2是脚本或者自动化的返回值,类型为Object
示例
api调用后打印出请求用户信息和返回值
1.示例api(test)配置好调用后处理调用脚本和脚本函数 如:postHandle
2.调用后脚本函数如下
javascript
export function postHandle(ctx, retValue) {
console.log('retValue',retValue);
var account=ctx.request.getAttribute('account');
console.log('account',account);
}
3.调用API
打印信息如下:
text
retValue {date=Fri May 05 11:02:19 CST 2023}
account {
"avatar": "c4b936e826fe45b38e1b4072c79a7a79.jpg",
"companyId": "g09aj7cus3d8s",
"createTime": 1664196780322,
"email": "zhangsan@informat.cn",
"id": "zhangsan",
"isValid": true,
"mobileNo": "19012345678",
"name": "张三",
"updateTime": 1683254561000,
"userName": "zhangsan",
"valid": true
}
错误处理
当调用的脚本或者自动化程序出错时,会返回500错误,并且会返回JSON格式的错误信息,错误信息的格式如下
text
{
requestId:String,//请求ID
message:String,//错误信息,
code:Integer,//业务发生错误时的错误码
}
如果不希望在出错的情况下返回默认信息,需要开启在调用错误后执行
,开启后在执行的脚本或者自动化出错后,将会执行错误处理脚本,
错误处理脚本接受两个参数,参数1是客户端传递的请求信息,类型为APIContext
。参数2是脚本或者自动化的错误信息,结构为APIError
错误处理脚本可以调用InformatHttpResponse
完成自定义返回值和状态码。
示例
如果API调用出错默认情况下API返回的HTTP状态码是500,有些场景比如对接第三方系统,希望出错时也返回200状态码,而不是500。这时可以通过错误处理来完成自定义返回值和状态码。
1.示例api(test)配置好错误处理调用脚本和脚本函数 如:errorHandle
2.错误处理调用脚本函数如下:
javascript
export function errorHandle(ctx, apiError) {
var json=informat.utils.toJSON(apiError);
var content=informat.utils.stringToBytes(json,"UTF-8");
var response=ctx.response;
response.setContentType("application/json;charset=UTF-8");
response.setStatus(200);
response.getOutputStream().write(content);
response.setContentLength(content.length);
}
3.调用API
如果出错了会返回状态码:200,返回值:
json
{
"code": 270001,
"message": "test error",
"requestId": "d6iaunfx9vm18"
}
数据结构
APIContext
的结构如下
text
{
headers:Object,//请求头
cookies:Object,//请求的cookie
query:Object,//请求的查询参数
body:String,//POST请求的body
url:String,//完整的请求路径
appId:String,//api所属的appId
path:String,//api的路径
method:String,//http请求的方法,
getParts():Part//上传的文件
request:InformatHttpRequest,//HTTP请求对象
response:InformatHttpResponse,//HTTP响应对象
}
InformatHttpRequest
的结构如下
text
{
Object getAttribute(String name);//获取指定名称的属性
Enumeration<String> getAttributeNames();//获取所有属性的名称
String getCharacterEncoding();//获取当前 HTTP 请求的字符编码
String getParameter(String name);//获取指定名称的请求参数的值
Enumeration<String> getParameterNames();//获取当前 HTTP 请求中包含的所有参数名称的枚举
String[] getParameterValues(String name);//获取指定名称的请求参数的所有值
Map<String, String[]> getParameterMap();//获取所有请求参数的键值对
String getProtocol();//获取客户端使用的协议(例如 HTTP/1.1)
String getScheme();//获取客户端使用的协议(例如 http 或 https)
String getServerName();//获取当前 Web 应用所在的服务器的主机名
String getRemoteAddr();//获取发送请求的客户端的 IP 地址
String getRemoteHost();//获取发送请求的客户端的主机名
int getRemotePort();//获取发送请求的客户端使用的端口号
void setAttribute(String name, Object o);//将指定名称的属性设置为指定的值
void removeAttribute(String name);//从此请求中删除指定名称的属性
boolean isSecure();//如果此请求使用安全协议(例如 HTTPS)进行传输,则返回 true;否则返回 false
int getServerPort();//获取当前 Web 应用所在的服务器的端口号
String getContentType();//获取 HTTP 请求的内容类型
String getAuthType();//返回用于请求的身份验证方案的名称
Cookie[] getCookies();//返回包含此请求中包含的所有 cookie 的数组
String getHeader(String name);//获取指定名称的请求头的值
Enumeration<String> getHeaders(String name);//获取指定名称的请求头的所有值
Enumeration<String> getHeaderNames();//获取当前 HTTP 请求中包含的所有请求头的名称的枚举
String getMethod();//获取请求的 HTTP 方法,例如 GET、POST 等
String getPathInfo();//获取请求 URL 中与 Servlet 映射匹配的部分之后的路径
String getContextPath();//返回与请求关联的 web 应用程序的上下文路径
String getQueryString();//获取请求 URL 中的查询字符串部分
String getRemoteUser();//获取发送请求的客户端的用户名
java.security.Principal getUserPrincipal();
String getRequestURI();//获取请求的 URI
String getServletPath();//获取客户端请求的 Servlet 路径
Collection<Part> getParts();//获取 HTTP POST 请求中的所有 Part 组件
}
InformatHttpResponse
的结构如下
text
{
String getCharacterEncoding();//返回响应的字符编码
String getContentType();//返回响应的内容类型
ServletOutputStream getOutputStream();//返回一个ServletOutputStream,用于向响应输出流中写入字节
PrintWriter getWriter();//获取一个PrintWriter对象,用于向响应输出流中写入字符
void setCharacterEncoding(String charset);//设置响应内容的字符编码
void setContentLength(int len);//设置响应内容的长度
void setContentLengthLong(long len);//设置响应内容的长度,与setContentLength方法相似。但是,它支持更长的响应内容长度
void setContentType(String type);//设置响应内容的MIME类型
boolean containsHeader(String name);//返回指定名称的标头是否已设置
String encodeURL(String url);//对指定的URL进行编码,以便在发送响应时使用
void sendError(int sc, String msg);//向客户端发送错误代码和消息,并清除响应缓冲区
void sendError(int sc);//向客户端发送错误代码,并清除响应缓冲区
void sendRedirect(String location);//重定向到指定的URL
void setHeader(String name, String value);//设置响应头部的指定名称的值
void addHeader(String name, String value);//添加指定名称和值的标头到响应
void setDateHeader(String name, long date);//设置指定名称和值的日期标头,表示响应的发送日期
void addDateHeader(String name, long date);//添加指定名称和值的日期标头,表示响应的发送日期
void setIntHeader(String name, int value);//设置指定名称和值的整数标头到响应
void addIntHeader(String name, int value);//添加指定名称和值的整数标头到响应
void setStatus(int sc);//设置响应状态码
int getStatus();//获取响应状态码
String getHeader(String name);//返回指定名称的响应头的值
Collection<String> getHeaders(String name);获取指定名称的响应头的所有值
int getBufferSize();//返回响应输出缓冲区的大小
void setBufferSize(int size);//设置响应缓冲区的大小
void flushBuffer();//刷新响应输出流
void reset();//清空响应缓冲区
void resetBuffer();//清空响应缓冲区
boolean isCommitted();//返回是否已经提交响应
}
Part
的结构如下
text
{
name:String,//上传时指定的名称
contentType:String,//文件类型
size:Integer,//文件大小
submittedFileName:String,//文件的原始名称,
save(path),//保存本地沙盒中,
saveStorage(path),//保存到共享存储中
saveAttachment(tableId,fieldId):TableAttachment//将文件保存为附件字段
}
APIError
的结构如下
text
{
requestId:String,//请求ID
message:String,//错误信息
code:Integer//错误码
}
脚本函数格式
当调用类型为调用脚本
时,需要在脚本文件中使用export
语法将调用函数导出,脚本函数需要接受一个ctx参数。
例如我们要实现一个通过API返回当前时间的功能,调用文件为 apitest.js,其中有一个获取当前时间的函数为 getTime
apitest.js
javascript
export function getTime(ctx){
return new Date()
}
ctx参数的类型为 APIContext
JSON
当返回值类型为JSON
时,将会返回JSON格式的文本,HTTP response`` 的
content-type`` 将会被设置为application/json;charset=UTF-8
。 调用的自动化
程序或者脚本
函数需要返回对象格式,系统会自动将对象序列化为JSON
字符串。返回内容的
下面是一个使用脚本返回用户输入参数的例子
javascript
export function returnJSON(ctx) {
const ret={
input:ctx.query.input,
date:new Date()
}
return ret;
}
shell
https://next.informat.cn/web0/api/croe0zft168y3/returnJSON?input=abc
json
{"input":"abc","date":1670157677104}
ℹ️ 提示
Date类型将会按照时间戳的形式返回
文本
当返回值类型为文本
时,将会返回纯文本,HTTP response 的content-type 将会被设置为text/plain;charset=UTF-8
。 调用的自动化
程序或者脚本
函数可以返回任意格式。如果是对象格式的返回值,系统会调用该对象的toString
方法将对象转换为字符串。如果返回值为null,则会返回空的字符串。
下面是一个使用脚本返回用户输入参数的例子
javascript
export function returnText(ctx) {
const list=[];
for(const key in ctx.query){
list.push(key+"="+ctx.query[key])
}
return list.join(',')
}
shell
https://next.informat.cn/web0/api/croe0zft168y3/returnText?a=1&b=2
txt
a=1,b=2
下载文件
当返回值类型为文件
时,返回一个文件流。调用的自动化
程序或者脚本
函数需要返回的结构如下
text
{
path:String,//本地存储沙盒中的文件路径
storagePath:String,//共享存储中的文件路径
name:String,//文件名称
contentDisposition:String,//文件的显示方式,可选值为 inline,attachment,默认值为attachment
}
当contentDisposition
的类型为attachment
时浏览器将会自动下载文件,当类型为inline
时浏览器将会使用内置的编辑器预览文件。 如果path为空或者path指定的文件不存在,则会返回404错误。 如果同时指定了path和storagePath会优先使用下载文件
下面是一个下载文件的例子
javascript
export function returnFile(ctx) {
return{
path:'path/test.jpg',
name:'test.jpg',
contentDisposition:'attachment'
}
}
shell
https://next.informat.cn/web0/api/croe0zft168y3/returnFile?a=1&b=2
txt
返回图片
下面是一个通过http获取到的文件来进行返回:
javascript
export const getFilePath = () => {
const req = {
url:'https://app.informat.cn/file/5bf495fd7c9d4df5896d186cc2707264_p.jpg',
}
const rsp = informat.http.request(req);
rsp.saveBodyAsFile('api/demo.jpg');
return {
path: 'api/demo.jpg',//本地存储沙盒中的文件路径
name: '文件名称.jpg',//文件名称
contentDisposition:'inline',//文件的显示方式,可选值为 inline,attachment,默认值为attachment
}
}
请求后浏览器将会在线预览demo.jpg
页面重定向
当返回值类型为重定向
时,将返回HTTP CODE 302,调用的自动化
程序或者脚本
函数需要按照字符串的格式返回重定向的URL地址
下面是一个重定向的例子
javascript
export function returnRedirect(ctx) {
return "https://informat.cn"
}
shell
https://next.informat.cn/web0/api/croe0zft168y3/returnRedirect
txt
请求后浏览器将会重定向到`https://informat.cn`
上传文件
当需要上传文件时,需要使用ctx.getParts()
获取用户上传的文件,然后存储到本地沙盒中,以下是一个上传文件的例子
javascript
export function uploadFile(ctx) {
const result=[];
ctx.getParts().forEach(p=>{
p.save(p.submittedFileName);
result.push(p.name+"/"+p.contentType+'/'+p.size+'/'+p.submittedFileName);
})
return result.join(',')
}
shell
curl -X POST -H "Content-Type: multipart/form-data" -F "data=@logo1.png" -F "data2=@logo2.jpg" https://next.informat.cn/web0/api/croe0zft168y3/uploadFile
json
[
{"contentType":"image/png","name":"data","size":5684,"submittedFileName":"logo1.png"},
{"contentType":"image/jpeg","name":"data2","size":7757,"submittedFileName":"logo2.jpg"}
]
限流
限流(Rate Limiting)是一种控制API请求速率的技术,用于防止服务器资源被过度使用或滥用。通过设置限流规则,可以确保API服务的稳定性和可靠性。 平台可以针对每个API开启请求限流的功能。可以设置的参数如下:
- 每秒并发量:是指一秒内能够处理的请求数量,0表示不限制。
- 超时时长(毫秒):等待请求的最长时间。负值视为零。
- 限流标识:限流规则的唯一标识,推荐把请求方IP作为限流标识。
示例
API限流:同一个ip每秒只能调用一次,可使用jmeter
或使用curl
命令进行测试。
bash
for i in {1..10}; do
echo "Request $i"
curl -i -X POST {接口URL} \
-H "Content-Type: application/json" \
-d '{"key": "value"}'
sleep 0.1
done