-
Notifications
You must be signed in to change notification settings - Fork 757
Description
详细描述这个 Bug
问题描述
使用阿里云 OSS (Alibaba Cloud OSS) 作为 S3 图床/存储后端时,即使 AccessKey、SecretKey 和 Endpoint 配置正确,连接测试也会失败,返回 403 Forbidden。
经过排查,原因是 NoteGen 在构造 S3 请求时强制使用了 Path-Style (https://endpoint/bucket),而阿里云 OSS 对这种请求格式的签名校验十分严格(或者需要特定的 Host 头配置),导致默认生成的签名无法通过校验。
复现步骤
- 打开 NoteGen 设置 -> 图床/存储设置。
- 选择 S3 兼容存储。
- 填入阿里云 OSS 配置:
- AccessKeyId:
LTAI...(有效密钥) - SecretAccessKey:
...(有效密钥) - Bucket:
my-bucket-name - Region:
oss-cn-beijing - Endpoint:
https://oss-cn-beijing.aliyuncs.com
- AccessKeyId:
- 点击“测试连接”。
期望行为
连接成功 (HTTP 200)。
实际行为
连接失败,控制台或日志显示 HTTP 403 Forbidden。
技术分析
问题出在 src/lib/imageHosting/s3.ts 中的 testS3Connection 和其他请求构造逻辑。
NoteGen 目前的代码逻辑如下:
const endpoint = config.endpoint || `https://s3.${config.region}.amazonaws.com`;
const url = `${endpoint}/${config.bucket}`; // 强制 Path-Style当 Endpoint 为 https://oss-cn-beijing.aliyuncs.com 时,请求 URL 变为:
https://oss-cn-beijing.aliyuncs.com/my-bucket-name
此时 Host 头是 oss-cn-beijing.aliyuncs.com。阿里云 OSS 收到此类请求时,可能无法正确解析 Bucket 或者认为签名不匹配。
相比之下,标准的 AWS SDK 或其他工具通常会自动使用 Virtual-Hosted Style:
https://my-bucket-name.oss-cn-beijing.aliyuncs.com
临时解决方案 (用户侧)
目前用户无法通过常规配置绕过此问题,除非将 Endpoint 修改为 Bucket 域名并将 Bucket 字段留空(但这会导致路径拼接错误)。
建议修复方案
建议在 src/lib/imageHosting/s3.ts 中增加对 Virtual-Hosted Style 的支持,或者自动检测阿里云 OSS Endpoint。
修改建议 (伪代码):
const endpoint = config.endpoint || `https://s3.${config.region}.amazonaws.com`;
let url;
// 简单的判断逻辑:如果 endpoint 包含 aliyuncs.com,使用 Virtual-Hosted Style
// 或者提供一个开关 forcePathStyle: boolean
if (endpoint.includes('aliyuncs.com') && !endpoint.includes(config.bucket)) {
// 构造 Virtual-Hosted URL: https://bucket.region.aliyuncs.com
// 注意:这里需要从 endpoint 中提取协议头,或者假设是 https
const protocol = endpoint.split('://')[0];
const domain = endpoint.split('://')[1];
url = `${protocol}://${config.bucket}.${domain}`;
} else {
url = `${endpoint}/${config.bucket}`;
}附:复现脚本 (Node.js)
可以使用以下脚本验证该问题(证明 Credentials 是好的,只是 URL 构造方式导致了 403):
// repro-notegen.js
const https = require('https');
const crypto = require('crypto');
// 填入阿里云配置
const config = {
accessKeyId: "YOUR_AK",
secretAccessKey: "YOUR_SK",
region: "oss-cn-beijing",
bucket: "YOUR_BUCKET",
endpoint: "https://oss-cn-beijing.aliyuncs.com",
};
// ... (此处省略 AWS V4 签名实现代码,这部分代码证明了手动构造 Path-Style 请求会复现 403)NoteGen 版本
v0.22.4
操作系统
Windows
报错日志
No response