关于 sasjs-adapter
为浏览器和 Node.js 提供调用 SAS 服务与作业的 TypeScript 库,通过统一 API 支持 SAS9、SASVIYA 和 SASJS。适合需要在 JavaScript 应用中提交 SAS 数据并读取结果的开发者。
主要功能
- 01统一调用三类 SAS 服务
- 02将输入表序列化为 CSV
- 03支持参数传输与文件上传
- 04管理认证与会话
- 05记录请求历史并可读取日志
适用场景
- 01从浏览器提交数据表并调用 SAS 作业
- 02在 Node.js 中连接 Viya 并提交作业
- 03调试请求并检查 SAS 日志
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ sasjs/ skills --skill sasjs-adapter安装后在 Claude Code 中输入/sasjs-adapter确认已加载。
详细介绍
@sasjs/adapter
@sasjs/adapter 是一个 TypeScript 库,可从浏览器或 Node 调用 SAS 服务/作业,并通过统一的 API 支持三种服务器类型:SAS9、SASVIYA、SASJS。
基本设置
import SASjs from '@sasjs/adapter'
const sasjs = new SASjs({
serverUrl: 'https://sas.example.com',
serverType: 'SASVIYA', // SAS9 | SASVIYA | SASJS
appLoc: '/Public/app/myapp', // root folder of deployed services
contextName: 'SAS Job Execution compute context', // Viya only
debug: false
})
request() - 输入(JS -> SAS)
签名
sasjs.request(
sasJob: string,
data: { [key: string]: any[] } | null,
config?: { [key: string]: any }, // merged over SASjsConfig
loginRequiredCallback?: () => any,
authConfig?: AuthConfig, // Viya tokens for Node usage
extraResponseAttributes?: ExtraResponseAttributes[] // ['log'] | ['file'] | ['data']
)
sasJob:相对于appLoc解析的路径(不带前导斜杠),或绝对路径。它会成为 SAS_program参数。data:一个对象,其键会成为 SAS 中的 work 数据集。如果服务不需要输入,可以是null。config:仅对本次调用生效的配置,会覆盖构造函数配置。
data 对象 - 表,而非任意 JSON
data 中的每个键都必须对应一个普通对象数组。每个键会成为一个以该键命名的 SAS work 数据集;数组中的每个对象是一行;每个属性是一列。
const res = await sasjs.request('services/common/getdata', {
customers: [
{ id: 1, name: 'Acme', active: true },
{ id: 2, name: 'Globex', active: false }
],
config: [{ rootdir: '/tmp', retries: 3 }] // even a single-row "config" table
})
在 SAS 端,这些数据会作为 work.customers 和 work.config 接收。
输入验证规则
发送前,适配器会验证 data(参见 validateInput)。如果违反规则,Promise 会以 ErrorResponse 拒绝:
data必须为null或普通对象(不能是数组或原始值)。- 每个表的键必须以字母或下划线开头:
/^[a-zA-Z_][a-zA-Z0-9_]*$/。不允许以数字开头。 - 表名不得超过 32 个字符(SAS 名称长度限制)。
- 每个键对应的值都必须是对象数组。不允许出现非对象行。
- 任意行中的属性都不能为
undefined(必须是null、字符串、数字或布尔值)。
表如何序列化为 CSV
每个表都会通过 convertToCSV 转换为 CSV。转换时会识别数据类型:
- 字符串列:仅当包含逗号、制表符、换行符或引号时才加引号。内部的
"会转义为""。 - 数字列:不加引号。
- 数字列中的 null / 空值:转换为
.(SAS 缺失值)。 - 列类型推断:适配器会扫描每列的所有行。如果某列同时包含
null/number值和特殊缺失值字符串(.a-.z、_),则该列的类型为best.。否则,第一个非空值决定该列是chars还是number。 - 列格式标头:CSV 的第一行是以空格分隔的格式规范,例如
name:$char20. id:best.;SAS 端会使用它来指定输入格式。 - 字节大小长度检查:字符串值按 UTF-8 字节数计量。如果任何值超过 32765 字节,请求会抛出
The max length of a string value in SASjs is 32765 characters. - 格式表:以
$为前缀的键(例如$customers)会被视为customers表的格式定义,不会作为单独的数据集发送。其formats属性将列名映射到 SAS 格式。
两种传输模式
适配器会根据负载大小和服务器类型选择传输方式(参见 WebJobExecutor):
- 基于参数(Viya Web / SASjs 服务器的默认方式,适用于小型负载):每个表的 CSV 会作为名为
sasjs{N}data的表单字段追加(N = 1、2、...)。sasjs_tables字段会以空格分隔的形式列出表名。如果单个 CSV 超过 16000 个字符,则会拆分为多个块:sasjs{N}data0存放块数,sasjs{N}data1..N存放各块内容。 - 文件上传(始终用于 SAS 9;当
JSON.stringify(data)超过 500000 个字符或包含;时用于 Viya/SASjs):每个表都会作为 CSV 文件({tableName}.csv)追加到 multipart 表单数据中。
两种情况下,请求体都是 multipart/form-data;当 debug: true 时,会包含调试参数(_debug=131、_omittextlog=false、_omitSessionResults=false)。
request() - 输出(SAS -> JS)
响应结构取决于 extraResponseAttributes
默认情况(没有 extraResponseAttributes):解析后的值是解析得到的 webout 对象本身,也就是 SAS 服务写入 _webout 的任意 JSON:
// SAS service wrote: {"mydata":[{"COL1":"x","COL2":1}]}
const res = await sasjs.request('services/getdata', { in: [{ a: 1 }] })
// res === { mydata: [{ COL1: 'x', COL2: 1 }] }
// res.mydata[0].COL1 // note UPPERCASE column names
带有 extraResponseAttributes 时(例如 ['log']):结果会被包装:
const res = await sasjs.request('services/getdata', { in: [{ a: 1 }] }, {}, undefined, undefined, ['log'])
// res === { result: { mydata: [...] }, log: '<sas log string>' }
ExtraResponseAttributes 的取值为 'file' | 'data' | 'log'。当前版本仅完整实现了 log。
名称大小写
- 响应中的表名为小写——这是由 SAS 端的
%webout/mp_jsonout宏强制执行的,而非适配器。适配器会原样传递 webout JSON。 - 列名为大写——SAS 数据集变量名会由 SAS 自身转换为大写,适配器不会更改其大小写。
SAS 服务必须生成的内容
服务必须将有效的 JSON 写入 _webout。通常通过 %webout(来自 @sasjs/core)实现,该宏会封装 mp_jsonout。JSON 结构是一个对象,其键为表名,每个键对应一个行对象数组:
%webout(OPEN)
%webout(OBJ, work.customers) /* -> {"customers":[{...}]} */
%webout(CLOSE)
调试模式
当 config.debug 为 true 时:
- SAS 9:原始响应是一个字符串,包含日志和 webout,两者由
>>weboutBEGIN<<和>>weboutEND<<分隔。适配器会提取标记之间的 JSON。 - Viya(web/JES):调试响应通过
parseSasViyaDebugResponse/parseSasViyaLogDebugResponse解析,以分离日志和 webout JSON。 - Viya(compute API):日志会从 compute 会话单独获取。
在所有情况下,开启调试并设置 extraResponseAttributes: ['log'] 后,都可以通过 res.log 获取 SAS 日志。
请求历史
每个已执行的请求都会追加到内存中的历史记录中(上限为 requestHistoryLimit,默认为 10):
sasjs.getSasRequests()
// SASjsRequest[]: { serviceLink, timestamp, sourceCode, generatedCode, logFile, SASWORK }
只有在 debug: true 时才会填充 sourceCode 和 generatedCode。历史记录采用环形缓冲区——超过上限时会丢弃最旧的条目。
身份验证
- SAS 9:
sasjs.logIn(username, password)(通过表单向存储过程服务进行身份验证)。会话 Cookie 会自动管理。 - Viya:OAuth 客户端/密钥(客户端凭据授权)或授权码流程;令牌会自动刷新。Node 用法通过 CLI(
sasjs add cred)配置。对于 Node,将authConfig(客户端/密钥/访问/刷新令牌)传递给request()。 - SASJS server:针对 sasjs/server API 的基于令牌的身份验证。
主要类 / 模块
SASjs- 主入口:request()、logIn()/logOut()、uploadFile()、executeScript()、startComputeJob()、deployServicePack()RequestClient- HTTP 层;保存请求历史(getRequests())、CSRF 令牌和身份验证标头WebJobExecutor- SAS 9 STP、Viya web JES 和 SASjs server web(multipart form POST)ComputeJobExecutor- Viya compute API(在指定上下文中直接提交代码)JesJobExecutor- Viya JES API(通过 jobs API 提交作业,而非 web 应用)SasjsJobExecutor- SASjs server web 执行SessionManager- Viya compute 会话生命周期管理SASViyaApiClient/SAS9ApiClient/SASjsApiClient- 各平台的底层客户端(很少需要直接使用)file/工具 - 向 SAS 上传文件(处理二进制内容)
提示
- 开发时设置
debug: true,以便在响应中显示 SAS 日志。 - 始终处理
response.status/ 错误响应——SAS 端错误(例如来自%mp_abort的错误)会出现在 JSON 中,不一定会作为 HTTP 错误返回。 - 对于大型负载,优先使用 CSV 上传或流式文件,而非 JSON 输入表。
- 确保
appLoc与用于部署的sasjsconfig.json中的appLoc一致。 - SAS 返回的列名为大写。如果前端需要小写,应在 JS 中进行映射,而不是尝试强制更改 SAS 的大小写。
- 数值输入列中的
null会变为 SAS 缺失值(.);字符列中的空字符串会保留为空字符串。不要使用undefined——验证会拒绝它。
在不使用打包器的情况下使用适配器(零构建 / 严格 CSP 前端)
包根目录中的 index.js 是一个 UMD 包,会公开全局对象 SASjs。用法(取自最小种子应用):
- 在 package.json 中添加
"prepare": "cp node_modules/@sasjs/adapter/index.js src/sasjs.js"(在npm i时运行)。 - 在应用脚本之前添加
<script src="sasjs.js"></script>。 - 通过隐藏的自定义元素进行配置:
<sasjs serverType="SASJS" appLoc="/Public/app/myapp" debug="false"></sasjs>,并使用document.querySelector('sasjs')读取属性。如果应用由 SAS 本身提供,则省略serverUrl——同源请求可直接正常工作(符合 CSPdefault-src 'self')。
限制
此技能是 @sasjs/adapter 库的静态参考资料——提供有关 API、请求 / 响应格式、身份验证和 CSV 序列化的指南。它不会执行代码、运行 shell 命令、访问文件系统、连接数据库或发起网络请求。所有代码示例仅供说明;用户必须将其集成到自己的应用中。有关身份验证令牌的说明描述的是适配器库在运行时管理的内容——此技能本身不会读取、写入或访问这些值。