[GH-ISSUE #796] [bug] 阿里云 OSS 连接失败 (S3 兼容性问题 / 强制 Path-Style 导致 403) #593

Open
opened 2026-03-02 03:40:43 +03:00 by kerem · 0 comments
Owner

Originally created by @xianggau on GitHub (Dec 17, 2025).
Original GitHub issue: https://github.com/codexu/note-gen/issues/796

详细描述这个 Bug

问题描述

使用阿里云 OSS (Alibaba Cloud OSS) 作为 S3 图床/存储后端时,即使 AccessKey、SecretKey 和 Endpoint 配置正确,连接测试也会失败,返回 403 Forbidden

经过排查,原因是 NoteGen 在构造 S3 请求时强制使用了 Path-Style (https://endpoint/bucket),而阿里云 OSS 对这种请求格式的签名校验十分严格(或者需要特定的 Host 头配置),导致默认生成的签名无法通过校验。

复现步骤

  1. 打开 NoteGen 设置 -> 图床/存储设置。
  2. 选择 S3 兼容存储。
  3. 填入阿里云 OSS 配置:
    • AccessKeyId: LTAI... (有效密钥)
    • SecretAccessKey: ... (有效密钥)
    • Bucket: my-bucket-name
    • Region: oss-cn-beijing
    • Endpoint: https://oss-cn-beijing.aliyuncs.com
  4. 点击“测试连接”。

期望行为

连接成功 (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

Originally created by @xianggau on GitHub (Dec 17, 2025). Original GitHub issue: https://github.com/codexu/note-gen/issues/796 ### 详细描述这个 Bug # 问题描述 使用阿里云 OSS (Alibaba Cloud OSS) 作为 S3 图床/存储后端时,即使 AccessKey、SecretKey 和 Endpoint 配置正确,连接测试也会失败,返回 `403 Forbidden`。 经过排查,原因是 NoteGen 在构造 S3 请求时强制使用了 Path-Style (`https://endpoint/bucket`),而阿里云 OSS 对这种请求格式的签名校验十分严格(或者需要特定的 Host 头配置),导致默认生成的签名无法通过校验。 ## 复现步骤 1. 打开 NoteGen 设置 -> 图床/存储设置。 2. 选择 S3 兼容存储。 3. 填入阿里云 OSS 配置: - **AccessKeyId**: `LTAI...` (有效密钥) - **SecretAccessKey**: `...` (有效密钥) - **Bucket**: `my-bucket-name` - **Region**: `oss-cn-beijing` - **Endpoint**: `https://oss-cn-beijing.aliyuncs.com` 4. 点击“测试连接”。 ## 期望行为 连接成功 (HTTP 200)。 ## 实际行为 连接失败,控制台或日志显示 HTTP 403 Forbidden。 ## 技术分析 问题出在 `src/lib/imageHosting/s3.ts` 中的 `testS3Connection` 和其他请求构造逻辑。 NoteGen 目前的代码逻辑如下: ```typescript 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。 **修改建议 (伪代码):** ```typescript 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): ```javascript // 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_
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/note-gen#593
No description provided.