Skip to content

API

概述

API允许外部系统以HTTP协议的形式和应用交互,每一个API拥有一个唯一的访问路径,在HTTP请求到达时,执行配置的自动化程序或者脚本函数,将执行结果按照配置的格式返回给调用端。 api调用

ℹ️ 重要信息

  • 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