| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- /**
- * 部署后 OSS 配置校验: 探查 bucket 实际 region, 跟 env 里配的 region + endpoint 对比,
- * 不一致就退出非 0, 阻止 deploy 走完。
- *
- * 用法:
- * node deploy-package/scripts/check-oss-config.cjs [bucket]
- * OSS_BUCKET_NAME=xxx node deploy-package/scripts/check-oss-config.cjs
- *
- * 退出码:
- * 0 = 一致
- * 1 = bucket 不可访问 / AK 无权限
- * 2 = region 不一致
- * 3 = endpoint 不匹配
- */
- const fs = require('fs');
- const path = require('path');
- const envTxt = fs.readFileSync(path.join(__dirname, '..', '..', 'server', '.env.production'), 'utf8');
- const env = {};
- for (const line of envTxt.split(/\r?\n/)) {
- const m = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)\s*$/);
- if (m) env[m[1]] = m[2].replace(/^["']|["']$/g, '');
- }
- // 允许环境变量覆盖 (线上 .env 跟 .env.production 不同时用线上为准)
- const AK = process.env.OSS_ACCESS_KEY_ID || env.OSS_ACCESS_KEY_ID;
- const SK = process.env.OSS_ACCESS_KEY_SECRET || env.OSS_ACCESS_KEY_SECRET;
- const ENV_BUCKET = process.env.OSS_BUCKET_NAME || env.OSS_BUCKET_NAME;
- const ENV_REGION = process.env.OSS_REGION || env.OSS_REGION;
- const ENV_ENDPOINT = process.env.OSS_INTERNAL_ENDPOINT || process.env.OSS_ENDPOINT || env.OSS_INTERNAL_ENDPOINT || env.OSS_ENDPOINT;
- const BUCKET = process.argv[2] || ENV_BUCKET;
- if (!BUCKET) { console.error('❌ 缺 OSS_BUCKET_NAME'); process.exit(1); }
- if (!AK || !SK) { console.error('❌ 缺 AK/SK'); process.exit(1); }
- const OSS = require(path.join(__dirname, '..', '..', 'server', 'node_modules', 'ali-oss'));
- // 列举常见 region endpoint (按 aliyun 文档)
- const REGION_ENDPOINTS = {
- 'oss-cn-hangzhou': 'oss-cn-hangzhou.aliyuncs.com',
- 'oss-cn-shanghai': 'oss-cn-shanghai.aliyuncs.com',
- 'oss-cn-beijing': 'oss-cn-beijing.aliyuncs.com',
- 'oss-cn-shenzhen': 'oss-cn-shenzhen.aliyuncs.com',
- 'oss-cn-qingdao': 'oss-cn-qingdao.aliyuncs.com',
- 'oss-cn-zhangjiakou': 'oss-cn-zhangjiakou.aliyuncs.com',
- 'oss-cn-huabei-3': 'oss-cn-huabei-3.aliyuncs.com',
- 'oss-cn-huabei-5': 'oss-cn-huabei-5.aliyuncs.com',
- 'oss-cn-hangzhou-finance': 'oss-cn-hangzhou-finance.aliyuncs.com',
- 'oss-cn-shanghai-finance-1': 'oss-cn-shanghai-finance-1.aliyuncs.com',
- 'oss-cn-chengdu': 'oss-cn-chengdu.aliyuncs.com',
- 'oss-cn-hongkong': 'oss-cn-hongkong.aliyuncs.com',
- 'oss-cn-fuzhou': 'oss-cn-fuzhou.aliyuncs.com',
- 'oss-cn-wulanchabu': 'oss-cn-wulanchabu.aliyuncs.com',
- 'oss-cn-shenyang': 'oss-cn-shenyang.aliyuncs.com',
- 'oss-cn-nanjing': 'oss-cn-nanjing.aliyuncs.com',
- 'oss-cn-heyuan': 'oss-cn-heyuan.aliyuncs.com',
- };
- (async () => {
- console.log(`\n=== OSS 配置校验 ===`);
- console.log(`期望 bucket: ${BUCKET}`);
- console.log(`env region: ${ENV_REGION}`);
- console.log(`env endpoint: ${ENV_ENDPOINT}`);
- // 探查所有 region, 找 bucket 实际位置
- // 用 ExtranetEndpoint 提取 region(这是 OSS 返回的真值,不靠 hostId 猜)
- let actualRegion = null, actualEndpoint = null, actualInternal = null;
- for (const [r, ep] of Object.entries(REGION_ENDPOINTS)) {
- try {
- const c = new OSS({ accessKeyId: AK, accessKeySecret: SK, bucket: BUCKET, endpoint: ep, secure: true });
- const info = await c.getBucketInfo(BUCKET);
- const exEp = info.bucket?.ExtranetEndpoint || ep;
- const m = exEp.match(/oss-([a-z0-9-]+)\.aliyuncs\.com/);
- if (m) {
- actualRegion = m[1];
- actualEndpoint = exEp;
- actualInternal = info.bucket?.IntranetEndpoint || exEp.replace(/aliyuncs\.com$/, 'aliyuncs.com').replace(/oss-([a-z0-9-]+)\./, 'oss-$1-internal.');
- console.log(`\n✅ bucket 真实 region: ${actualRegion}`);
- console.log(` ExtranetEndpoint: ${info.bucket?.ExtranetEndpoint}`);
- console.log(` IntranetEndpoint: ${info.bucket?.IntranetEndpoint}`);
- console.log(` StorageClass: ${info.bucket?.StorageClass}`);
- console.log(` CreationDate: ${info.bucket?.CreationDate}`);
- break;
- }
- } catch (e) {
- // continue
- }
- }
- if (!actualRegion) {
- console.log('\n❌ 所有 region 都试过了, 无法访问 bucket. 检查 AK/SK 权限.');
- process.exit(1);
- }
- // 比较 region
- let pass = true;
- if (ENV_REGION !== actualRegion) {
- console.log(`\n❌ region 不一致! env=${ENV_REGION} 实际=${actualRegion}`);
- pass = false;
- } else {
- console.log(`\n✅ region 一致 (${actualRegion})`);
- }
- // 比较 endpoint (允许 internal/external 差异)
- const envEpHost = (ENV_ENDPOINT || '').replace(/^-internal\./, '').replace(/^https?:\/\//, '');
- const actualEpHost = (actualEndpoint || '').replace(/^https?:\/\//, '');
- if (envEpHost && actualEpHost && !envEpHost.includes(actualEpHost.split('.')[0])) {
- console.log(`❌ endpoint 不匹配! env=${ENV_ENDPOINT} 实际=${actualEndpoint}`);
- pass = false;
- } else {
- console.log(`✅ endpoint 匹配 (${actualEpHost})`);
- }
- if (!pass) {
- console.log(`\n⚠️ 建议:`);
- console.log(` 把 .env.production 里:`);
- console.log(` OSS_REGION=${actualRegion}`);
- console.log(` OSS_ENDPOINT=${actualEndpoint}`);
- console.log(` OSS_INTERNAL_ENDPOINT=${actualInternal}`);
- process.exit(2);
- }
- // 最后跑 list 确认能正常操作
- try {
- const c = new OSS({ accessKeyId: AK, accessKeySecret: SK, bucket: BUCKET, endpoint: actualEndpoint, secure: true });
- const r = await c.list({ 'max-keys': 1, delimiter: '/' });
- console.log(`\n✅ list 正常 (顶层 prefix: ${(r.prefixes || []).slice(0, 5).join(', ')})`);
- process.exit(0);
- } catch (e) {
- console.log(`\n❌ list 失败: ${e.code || e.message}`);
- process.exit(3);
- }
- })().catch(e => { console.error('异常:', e); process.exit(1); });
|