重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
b2c-webservices by salesforcecommercecloud/b2c-developer-tooling
npx skills add https://github.com/salesforcecommercecloud/b2c-developer-tooling --skill b2c-webservices此技能指导您如何使用 Service Framework 在 B2C Commerce 中实现 Web 服务集成。
Service Framework 提供了一种结构化的方式来调用外部服务,具备以下特性:
| 特性 | 描述 |
|---|---|
| 配置 | 在 Business Manager 中管理服务设置 |
| 速率限制 | 自动节流以保护外部系统 |
| 断路器 | 自动故障处理以防止级联故障 |
| 日志记录 | 通信日志记录,并过滤敏感数据 |
| 模拟 | 无需外部调用即可测试服务 |
| 类型 | 使用场景 | 协议 |
|---|---|---|
HTTP |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| REST API、Webhook |
| HTTP/HTTPS |
HTTPForm | 表单提交 | 使用表单编码的 HTTP/HTTPS |
FTP | 文件传输(已弃用) | FTP |
SFTP | 安全文件传输 | SFTP |
SOAP | SOAP Web 服务 | 使用 SOAP 的 HTTP/HTTPS |
GENERIC | 自定义协议 | 任意 |
服务在 管理 > 运营 > 服务 中配置:
| 组件 | 用途 |
|---|---|
LocalServiceRegistry | 创建服务实例 |
ServiceCallback | 定义请求/响应处理 |
Service | 具有通用方法的基类服务 |
Result | 包含状态和数据的响应对象 |
'use strict';
var LocalServiceRegistry = require('dw/svc/LocalServiceRegistry');
var myService = LocalServiceRegistry.createService('my.service.id', {
/**
* 在发送请求前进行配置
* @param {dw.svc.HTTPService} svc - 服务实例
* @param {Object} params - 传递给 service.call() 的参数
* @returns {string} 请求体
*/
createRequest: function (svc, params) {
svc.setRequestMethod('POST');
svc.addHeader('Content-Type', 'application/json');
return JSON.stringify(params);
},
/**
* 在成功调用后解析响应
* @param {dw.svc.HTTPService} svc - 服务实例
* @param {dw.net.HTTPClient} client - 包含响应的 HTTP 客户端
* @returns {Object} 解析后的响应
*/
parseResponse: function (svc, client) {
return JSON.parse(client.text);
},
/**
* 从日志中过滤敏感数据(生产环境必需)
* @param {string} msg - 要过滤的消息
* @returns {string} 过滤后的消息
*/
filterLogMessage: function (msg) {
return msg.replace(/("api_key"\s*:\s*")[^"]+"/g, '$1***"');
}
});
// 调用服务
var result = myService.call({ key: 'value' });
if (result.ok) {
var data = result.object;
} else {
var error = result.errorMessage;
}
| 回调 | 是否必需 | 描述 |
|---|---|---|
createRequest | 是* | 配置请求,返回请求体 |
parseResponse | 是* | 解析响应,返回结果对象 |
execute | 否 | 自定义执行逻辑(替换默认逻辑) |
initServiceClient | 否 | 创建/配置底层客户端 |
mockCall | 否 | 返回模拟响应(仅执行阶段) |
mockFull | 否 | 返回模拟响应(整个调用) |
filterLogMessage | 推荐 | 从日志中过滤敏感数据 |
getRequestLogMessage | 否 | 自定义请求日志消息 |
getResponseLogMessage | 否 | 自定义响应日志消息 |
*除非实现了 execute,否则必需
call() 方法返回一个 dw.svc.Result:
| 属性 | 类型 | 描述 |
|---|---|---|
ok | Boolean | 成功时为 true |
status | String | "OK"、"ERROR" 或 "SERVICE_UNAVAILABLE" |
object | Object | 来自 parseResponse 的响应 |
error | Number | 错误代码(例如 HTTP 状态码) |
errorMessage | String | 错误描述 |
unavailableReason | String | 服务不可用的原因 |
mockResult | Boolean | 如果来自模拟回调则为 true |
| 原因 | 描述 |
|---|---|
TIMEOUT | 调用超时 |
RATE_LIMITED | 超出速率限制 |
CIRCUIT_BROKEN | 断路器打开 |
DISABLED | 服务已禁用 |
CONFIG_PROBLEM | 配置错误 |
var result = myService.call(params);
if (result.ok) {
return result.object;
}
// 处理不同类型的错误
switch (result.status) {
case 'SERVICE_UNAVAILABLE':
switch (result.unavailableReason) {
case 'RATE_LIMITED':
// 稍后重试
break;
case 'CIRCUIT_BROKEN':
// 服务已宕机,使用备用方案
break;
case 'TIMEOUT':
// 请求超时
break;
}
break;
case 'ERROR':
// 检查 HTTP 状态码
if (result.error === 401) {
// 身份验证错误
} else if (result.error === 404) {
// 资源未找到
}
break;
}
throw new Error('Service error: ' + result.errorMessage);
生产环境需要日志过滤以防止敏感数据泄露:
var myService = LocalServiceRegistry.createService('my.service', {
createRequest: function (svc, params) {
// ... 配置请求
},
parseResponse: function (svc, client) {
return JSON.parse(client.text);
},
/**
* 从所有日志消息中过滤敏感数据
*/
filterLogMessage: function (msg) {
// 过滤 API 密钥
msg = msg.replace(/api_key=[^&]+/g, 'api_key=***');
// 过滤授权头
msg = msg.replace(/Authorization:\s*[^\r\n]+/gi, 'Authorization: ***');
// 过滤 JSON 中的密码
msg = msg.replace(/("password"\s*:\s*")[^"]+"/g, '$1***"');
return msg;
},
/**
* 自定义请求日志消息(可选)
*/
getRequestLogMessage: function (request) {
// 返回自定义消息,或返回 null 使用默认消息
return 'Request: ' + request.substring(0, 100) + '...';
},
/**
* 自定义响应日志消息(可选)
*/
getResponseLogMessage: function (response) {
// 返回自定义消息,或返回 null 使用默认消息
return 'Response received';
}
});
使用模拟回调进行测试,无需外部调用:
var myService = LocalServiceRegistry.createService('my.service', {
createRequest: function (svc, params) {
svc.setRequestMethod('GET');
svc.addParam('id', params.id);
return null;
},
parseResponse: function (svc, client) {
return JSON.parse(client.text);
},
/**
* 仅模拟执行阶段(createRequest 和 parseResponse 仍会运行)
*/
mockCall: function (svc, request) {
return {
statusCode: 200,
text: JSON.stringify({ id: 1, name: 'Mock Data' })
};
},
/**
* 或模拟整个调用(替换所有阶段)
*/
mockFull: function (svc, params) {
return { id: params.id, name: 'Full Mock Data' };
}
});
// 强制进入模拟模式
myService.setMock();
var result = myService.call({ id: 123 });
my.api.service)| 设置 | 描述 |
|---|---|
| 超时 | 最大等待时间(毫秒) |
| 速率限制 | 每时间单位的最大调用次数 |
| 启用断路器 | 启用自动故障处理 |
| 最大断路器调用次数 | 断路器打开前的调用次数 |
| 断路器间隔 | 跟踪故障的时间窗口 |
| 设置 | 描述 |
|---|---|
| ID | 凭证标识符 |
| URL | 服务的基础 URL |
| 用户 | 用于身份验证的用户名 |
| 密码 | 用于身份验证的密码 |
| 类 | 描述 |
|---|---|
dw.svc.LocalServiceRegistry | 创建服务实例 |
dw.svc.Service | 基础服务类 |
dw.svc.HTTPService | HTTP 服务方法 |
dw.svc.FTPService | FTP/SFTP 服务方法 |
dw.svc.SOAPService | SOAP 服务方法 |
dw.svc.Result | 服务调用结果 |
dw.svc.ServiceConfig | 服务配置 |
dw.svc.ServiceProfile | 速率限制/断路器配置 |
dw.svc.ServiceCredential | 身份验证凭证 |
dw.net.HTTPClient | 底层 HTTP 客户端 |
dw.net.FTPClient | 底层 FTP 客户端 |
dw.net.SFTPClient | 底层 SFTP 客户端 |
每周安装次数
64
代码仓库
GitHub 星标数
34
首次出现
2026年2月21日
安全审计
安装于
github-copilot59
codex56
cursor56
opencode55
gemini-cli54
amp54
This skill guides you through implementing web service integrations in B2C Commerce using the Service Framework.
The Service Framework provides a structured way to call external services with:
| Feature | Description |
|---|---|
| Configuration | Service settings managed in Business Manager |
| Rate Limiting | Automatic throttling to protect external systems |
| Circuit Breaker | Automatic failure handling to prevent cascade failures |
| Logging | Communication logging with sensitive data filtering |
| Mocking | Test services without external calls |
| Type | Use Case | Protocol |
|---|---|---|
HTTP | REST APIs, webhooks | HTTP/HTTPS |
HTTPForm | Form submissions | HTTP/HTTPS with form encoding |
FTP | File transfers (deprecated) | FTP |
SFTP | Secure file transfers | SFTP |
SOAP | SOAP web services | HTTP/HTTPS with SOAP |
GENERIC | Custom protocols | Any |
Services are configured in Administration > Operations > Services:
| Component | Purpose |
|---|---|
LocalServiceRegistry | Creates service instances |
ServiceCallback | Defines request/response handling |
Service | Base service with common methods |
Result | Response object with status and data |
'use strict';
var LocalServiceRegistry = require('dw/svc/LocalServiceRegistry');
var myService = LocalServiceRegistry.createService('my.service.id', {
/**
* Configure the request before it is sent
* @param {dw.svc.HTTPService} svc - The service instance
* @param {Object} params - Parameters passed to service.call()
* @returns {string} Request body
*/
createRequest: function (svc, params) {
svc.setRequestMethod('POST');
svc.addHeader('Content-Type', 'application/json');
return JSON.stringify(params);
},
/**
* Parse the response after a successful call
* @param {dw.svc.HTTPService} svc - The service instance
* @param {dw.net.HTTPClient} client - The HTTP client with response
* @returns {Object} Parsed response
*/
parseResponse: function (svc, client) {
return JSON.parse(client.text);
},
/**
* Filter sensitive data from logs (required for production)
* @param {string} msg - The message to filter
* @returns {string} Filtered message
*/
filterLogMessage: function (msg) {
return msg.replace(/("api_key"\s*:\s*")[^"]+"/g, '$1***"');
}
});
// Call the service
var result = myService.call({ key: 'value' });
if (result.ok) {
var data = result.object;
} else {
var error = result.errorMessage;
}
| Callback | Required | Description |
|---|---|---|
createRequest | Yes* | Configure request, return body |
parseResponse | Yes* | Parse response, return result object |
execute | No | Custom execution logic (replaces default) |
initServiceClient | No | Create/configure underlying client |
mockCall | No |
*Required unless execute is implemented
The call() method returns a dw.svc.Result:
| Property | Type | Description |
|---|---|---|
ok | Boolean | True if successful |
status | String | "OK", "ERROR", or "SERVICE_UNAVAILABLE" |
object | Object | Response from parseResponse |
error | Number | Error code (e.g., HTTP status) |
errorMessage |
| Reason | Description |
|---|---|
TIMEOUT | Call timed out |
RATE_LIMITED | Rate limit exceeded |
CIRCUIT_BROKEN | Circuit breaker open |
DISABLED | Service disabled |
CONFIG_PROBLEM | Configuration error |
var result = myService.call(params);
if (result.ok) {
return result.object;
}
// Handle different error types
switch (result.status) {
case 'SERVICE_UNAVAILABLE':
switch (result.unavailableReason) {
case 'RATE_LIMITED':
// Retry later
break;
case 'CIRCUIT_BROKEN':
// Service is down, use fallback
break;
case 'TIMEOUT':
// Request timed out
break;
}
break;
case 'ERROR':
// Check HTTP status code
if (result.error === 401) {
// Authentication error
} else if (result.error === 404) {
// Resource not found
}
break;
}
throw new Error('Service error: ' + result.errorMessage);
Production environments require log filtering to prevent sensitive data exposure:
var myService = LocalServiceRegistry.createService('my.service', {
createRequest: function (svc, params) {
// ... configure request
},
parseResponse: function (svc, client) {
return JSON.parse(client.text);
},
/**
* Filter sensitive data from all log messages
*/
filterLogMessage: function (msg) {
// Filter API keys
msg = msg.replace(/api_key=[^&]+/g, 'api_key=***');
// Filter authorization headers
msg = msg.replace(/Authorization:\s*[^\r\n]+/gi, 'Authorization: ***');
// Filter passwords in JSON
msg = msg.replace(/("password"\s*:\s*")[^"]+"/g, '$1***"');
return msg;
},
/**
* Custom request log message (optional)
*/
getRequestLogMessage: function (request) {
// Return custom message or null for default
return 'Request: ' + request.substring(0, 100) + '...';
},
/**
* Custom response log message (optional)
*/
getResponseLogMessage: function (response) {
// Return custom message or null for default
return 'Response received';
}
});
Use mock callbacks for testing without external calls:
var myService = LocalServiceRegistry.createService('my.service', {
createRequest: function (svc, params) {
svc.setRequestMethod('GET');
svc.addParam('id', params.id);
return null;
},
parseResponse: function (svc, client) {
return JSON.parse(client.text);
},
/**
* Mock the execute phase only (createRequest and parseResponse still run)
*/
mockCall: function (svc, request) {
return {
statusCode: 200,
text: JSON.stringify({ id: 1, name: 'Mock Data' })
};
},
/**
* Or mock the entire call (replaces all phases)
*/
mockFull: function (svc, params) {
return { id: params.id, name: 'Full Mock Data' };
}
});
// Force mock mode
myService.setMock();
var result = myService.call({ id: 123 });
my.api.service)| Setting | Description |
|---|---|
| Timeout | Maximum wait time in milliseconds |
| Rate Limit | Maximum calls per time unit |
| Circuit Breaker Enabled | Enable automatic failure handling |
| Max Circuit Breaker Calls | Calls before circuit opens |
| Circuit Breaker Interval | Time window for tracking failures |
| Setting | Description |
|---|---|
| ID | Credential identifier |
| URL | Base URL for the service |
| User | Username for authentication |
| Password | Password for authentication |
| Class | Description |
|---|---|
dw.svc.LocalServiceRegistry | Create service instances |
dw.svc.Service | Base service class |
dw.svc.HTTPService | HTTP service methods |
dw.svc.FTPService | FTP/SFTP service methods |
dw.svc.SOAPService | SOAP service methods |
dw.svc.Result | Service call result |
Weekly Installs
64
Repository
GitHub Stars
34
First Seen
Feb 21, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykWarn
Installed on
github-copilot59
codex56
cursor56
opencode55
gemini-cli54
amp54
Azure 升级评估与自动化工具 - 轻松迁移 Functions 计划、托管层级和 SKU
111,700 周安装
| Return mock response (execute phase only) |
mockFull | No | Return mock response (entire call) |
filterLogMessage | Recommended | Filter sensitive data from logs |
getRequestLogMessage | No | Custom request log message |
getResponseLogMessage | No | Custom response log message |
| String |
| Error description |
unavailableReason | String | Why service is unavailable |
mockResult | Boolean | True if from mock callback |
dw.svc.ServiceConfig | Service configuration |
dw.svc.ServiceProfile | Rate limit/circuit breaker config |
dw.svc.ServiceCredential | Authentication credentials |
dw.net.HTTPClient | Underlying HTTP client |
dw.net.FTPClient | Underlying FTP client |
dw.net.SFTPClient | Underlying SFTP client |