import crypto from 'node:crypto' import https from 'node:https' import { runtimeConfig } from '../src/config/runtime.js' function percentEncode(value: string): string { return encodeURIComponent(String(value || '')) .replace(/\+/g, '%20') .replace(/\*/g, '%2A') .replace(/%7E/g, '~') } function signAliyunRequest(params: Record, accessKeySecret: string): string { const canonicalizedQuery = Object.entries(params) .map(([key, value]) => `${percentEncode(key)}=${percentEncode(value)}`) .sort((left, right) => String(left[0]) < String(right[0]) ? -1 : String(left[0]) > String(right[0]) ? 1 : 0, ) .join('&') const stringToSign = `GET&${percentEncode('/')}&${percentEncode(canonicalizedQuery)}` const hmac = crypto.createHmac('sha1', `${accessKeySecret}&`) hmac.update(stringToSign) return hmac.digest('base64') } async function main() { const config = runtimeConfig.worker.sms console.log('当前短信配置:') console.log(' provider :', config.provider) console.log( ' accessKeyId :', config.accessKeyId ? `${config.accessKeyId.slice(0, 4)}...${config.accessKeyId.slice(-4)}` : '(空)', ) console.log( ' accessKeySecret :', config.accessKeySecret ? `${config.accessKeySecret.slice(0, 4)}...${config.accessKeySecret.slice(-4)}(长度 ${config.accessKeySecret.length})` : '(空)', ) console.log(' signName :', config.signName) console.log(' templateCode :', config.templateCode) console.log('') if (!config.accessKeyId || !config.accessKeySecret || !config.signName || !config.templateCode) { console.error('配置不完整,请检查 .env 中的 WORKER_SMS_* 配置') return } const phone = process.argv[2] || '13800000000' const params: Record = { AccessKeyId: config.accessKeyId, Action: 'SendSms', Format: 'JSON', Version: '2017-05-25', SignatureMethod: 'HMAC-SHA1', SignatureVersion: '1.0', SignatureNonce: crypto.randomUUID(), Timestamp: new Date().toISOString().replace(/\.\d{3}Z$/, 'Z'), PhoneNumbers: phone, SignName: config.signName, TemplateCode: config.templateCode, TemplateParam: JSON.stringify({ code: '123456' }), } const signature = signAliyunRequest(params, config.accessKeySecret) params.Signature = signature const queryString = Object.entries(params) .map(([key, value]) => `${percentEncode(key)}=${percentEncode(value)}`) .sort() .join('&') const url = `https://dysmsapi.aliyuncs.com/?${queryString}` console.log('stringToSign:') console.log( ' ', `GET&%2F&${percentEncode( Object.entries(params) .filter(([key]) => key !== 'Signature') .map(([key, value]) => `${percentEncode(key)}=${percentEncode(value)}`) .sort((left, right) => String(left[0]) < String(right[0]) ? -1 : String(left[0]) > String(right[0]) ? 1 : 0, ) .join('&'), )}`, ) console.log('') console.log(`发送测试短信到 ${phone}(验证码 123456)...`) https .get(url, (response) => { const chunks: Buffer[] = [] response.on('data', (chunk) => chunks.push(Buffer.from(chunk))) response.on('end', () => { const body = Buffer.concat(chunks).toString('utf8') console.log('响应:', body) }) }) .on('error', (error) => { console.error('请求失败:', error.message) }) } void main()