feat: resumable upload default use v2#446
Conversation
Summary of ChangesHello @YangSen-qn, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a significant upgrade to the resumable upload functionality by implementing a new version 2 API. It provides new classes and methods designed for improved resumable uploads, while gracefully deprecating the older API. The changes ensure that existing integrations continue to function by internally routing calls to the new V2 methods, making the transition seamless for users. The update also includes relevant examples and tests to reflect and validate the new V2 implementation. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
Code Quality Review SummaryOverall: The V2 API additions are well-structured and maintain backward compatibility through deprecation. However, there are issues that should be addressed. Critical Issues:
Maintainability Concerns:
Positive Notes:
|
There was a problem hiding this comment.
Code Review
This pull request aims to make v2 the default for resumable uploads by introducing V2 versions of methods and classes. The changes are in the right direction, but there are a few critical issues. A new example file examples/a.js seems to have been added by mistake and contains placeholder credentials, which is a security risk. More importantly, the wrapper functions like putFile and putStream do not correctly default to v2 as intended, and a helper function getDefaultPutExtraV2 also has a bug that causes it to default to v1. I've left specific comments on these issues.
examples/a.js
Outdated
| digest.Mac({ | ||
| accessKey: '**', | ||
| secretKey: '**' | ||
| }); |
There was a problem hiding this comment.
This file appears to be a test or example file that was accidentally committed. It contains hardcoded credentials (even as placeholders **), which is a major security risk and should not be in the repository. Also, the usage of digest.Mac is incorrect. It's a constructor and should be called with new, and its arguments are accessKey and secretKey strings, not an object. For example: new digest.Mac('accessKey', 'secretKey');. Please remove this file from the pull request.
qiniu/storage/resume.js
Outdated
| * @param {string} [fname] 请求体中的文件的名称 | ||
| * @param {Object} [params] 额外参数设置,参数名称必须以x:开头 | ||
| * @param {string | null} [mimeType] 指定文件的mimeType | ||
| * @param {string | null} [resumeRecordFile] DEPRECATED: 使用 `` 与 `` 代替;断点续传的已上传的部分信息记录文件路径 |
There was a problem hiding this comment.
[Documentation] Empty backticks in deprecation notice
The deprecation message has empty backticks that should reference the replacement properties.
| * @param {string | null} [resumeRecordFile] DEPRECATED: 使用 `` 与 `` 代替;断点续传的已上传的部分信息记录文件路径 | |
| * @param {string | null} [resumeRecordFile] DEPRECATED: 使用 `resumeRecorder` 与 `resumeKey` 代替;断点续传的已上传的部分信息记录文件路径 |
Same issue exists on line 68 for PutExtra.
Code Review SummaryThis PR introduces V2 upload API methods with improved defaults. I've identified one critical bug and several important issues: Critical Issues:
Documentation:
Performance:
Overall structure is sound. Please address the critical bug on line 1128 before merging. |
|
@xgopilot 在这个 pr 中有没有更好的办法在保证版本兼容性前提下让 PutExtra 中的 version 默认从 v1 调整到 v2 |
关于 PutExtra 默认版本的建议@YangSen-qn 你好!我已经仔细分析了这个 PR 的实现方案。关于你提出的问题 "有没有更好的办法在保证版本兼容性前提下让 PutExtra 中的 version 默认从 v1 调整到 v2",我有以下建议: 当前实现的问题当前方案通过创建
更好的解决方案我建议采用以下几种方案之一,按推荐优先级排序: 方案 1: 使用工厂函数(推荐 ⭐)优点:
实现: function PutExtra(...args) {
// 保持原有默认值 v1,确保向后兼容
this.version = args[6] || 'v1';
// ... 其他字段
}
// 新增工厂函数
PutExtra.createV2 = function(fname, params, mimeType, resumeRecordFile,
progressCallback, partSize, version,
metadata, resumeRecorder, resumeKey) {
const extra = new PutExtra(fname, params, mimeType, resumeRecordFile,
progressCallback, partSize, version || 'v2',
metadata, resumeRecorder, resumeKey);
return extra;
};使用方式: // 旧代码继续使用 PutExtra,默认 v1(向后兼容)
const putExtra = new PutExtra();
// 新代码使用工厂函数,默认 v2
const putExtraV2 = PutExtra.createV2();方案 2: 使用选项对象模式优点:
实现: function PutExtra(options) {
options = options || {};
this.fname = options.fname || '';
this.params = options.params || {};
this.mimeType = options.mimeType || null;
this.resumeRecordFile = options.resumeRecordFile || null;
this.progressCallback = options.progressCallback || null;
this.partSize = options.partSize || conf.BLOCK_SIZE;
// 允许显式指定默认版本,保持向后兼容
this.version = options.version !== undefined ? options.version : 'v1';
this.metadata = options.metadata || {};
this.resumeRecorder = options.resumeRecorder || null;
this.resumeKey = options.resumeKey || null;
}
PutExtra.createV2 = function(options) {
options = options || {};
if (options.version === undefined) {
options.version = 'v2';
}
return new PutExtra(options);
};方案 3: 继承方式(不太推荐)缺点: JavaScript 原型继承可能引入额外复杂性 function PutExtraV2(...args) {
PutExtra.call(this, ...args);
// 只覆盖默认版本
if (args[6] === undefined) {
this.version = 'v2';
}
}
PutExtraV2.prototype = Object.create(PutExtra.prototype);
PutExtraV2.prototype.constructor = PutExtraV2;关于向后兼容性重要考虑: 当前 PR 的方案虽然保留了旧的 API(
建议的兼容性策略: 如果要真正平滑过渡:
总结建议我强烈推荐方案 1(工厂函数),因为它:
同时,请务必修复当前代码中的 Bug( 希望这些建议对你有帮助!如果需要我详细展示某个方案的完整实现,请告诉我。 |
|
@xgopilot 在方案一中,怎么让用户感知到之前的构造方法已经废弃?这样用户可以使用新的构造方法。 方案 1: 使用工厂函数(推荐 ⭐) |
如何让用户感知 API 已废弃@YangSen-qn 关于如何在方案一中让用户感知旧的构造方法已废弃,有以下几种最佳实践: 方案 1: 使用
|
|
@xgopilot 上面的方案中为什么要使用 PutExtra.createV2 而不直接只用 PutExtra.create |
关于工厂函数命名的说明@YangSen-qn 这是个很好的问题!让我详细解释为什么推荐使用 推荐使用
|
|
@xgopilot 重新 Review 下这个 pr,特别是接口兼容性问题。 |
PR #446 Code Review - 接口兼容性专项分析经过仔细审查,我发现这个 PR 在接口兼容性方面有以下关键问题: ✅ 已改进的地方
❌ 兼容性问题(Critical)1. 隐式行为变更 - 这是一个 BREAKING CHANGE问题位置: // putFileV2 方法中 (line 960)
putExtra = putExtra || PutExtra.create(); // 默认创建 v2
// putFileV2 继续调用 (line 972)
putExtra = getDefaultPutExtra(putExtra, { key }); // 这里保持 putExtra 的 version影响分析: 用户现有代码如果使用 // 场景 1: 用户代码 (老版本 SDK)
const putExtra = new PutExtra();
// putExtra.version = 'v1' (默认)
resumeUploader.putFileV2(token, key, file, putExtra);
// 老版本: 会使用 v1
// 新版本: 仍会使用 v1 (因为 getDefaultPutExtra 保留了 version)
// 场景 2: 用户代码 (不传 putExtra)
resumeUploader.putFileV2(token, key, file);
// 老版本: 如果老版本有 putFileV2,会使用 v1 (因为 getDefaultPutExtra 设置 v1)
// 新版本: 会使用 v2 (因为 PutExtra.create() 默认 v2)
// ⚠️ 这是 BREAKING CHANGE!这意味着: 任何不传 2. 废弃警告位置不准确问题位置: exports.PutExtra = libUtil.deprecate(
PutExtra,
'PutExtra constructor is deprecated. Use PutExtra.create() for v2 uploads or explicitly specify version parameter.'
);问题:
建议的警告信息: 'PutExtra constructor defaults to v1 which is deprecated. Use PutExtra.create() for v2 (recommended), or explicitly pass version parameter.'3. JSDoc 文档与实际行为不一致问题位置:
这会造成用户困惑。 现状: // Line 74: PutExtra 构造函数
* @param {'v1' | 'v2'} [version] 分片上传版本 目前支持v1/v2版本 默认v1
// Line 111: PutExtra.create JSDoc
* @param {'v1' | 'v2'} [version] 分片上传版本 目前支持v1/v2版本 默认v2这是正确的,但用户需要非常仔细阅读文档才能理解两者差异。 4. 测试使用
|
| 场景 | 旧代码 | 新代码行为 | 是否兼容 | 风险级别 |
|---|---|---|---|---|
new PutExtra() + putFile() |
v1 | v1 | ✅ 兼容 | 低 |
new PutExtra() + putFileV2() |
v1 | v1 | ✅ 兼容 | 低 |
不传 putExtra + putFile() |
v1 | v1 | ✅ 兼容 | 低 |
不传 putExtra + putFileV2() |
v1 (假设) | v2 | ❌ 破坏性变更 | 高 |
PutExtra.create() + 任何方法 |
N/A (新 API) | v2 | ✅ 新功能 | 低 |
🔧 建议的改进方案
方案 A: 保守方案(推荐用于 minor 版本)
目标: 完全向后兼容,v2 是选择性加入
// putFileV2 的修改
ResumeUploader.prototype.putFileV2 = function (
uploadToken,
key,
localFile,
putExtra,
callbackFunc
) {
const preferredScheme = this.config.useHttpsDomain ? 'https' : 'http';
// 改为: 如果用户没有传 putExtra,使用 PutExtra.create()
// 如果用户传了 putExtra,尊重用户的选择
if (!putExtra) {
putExtra = PutExtra.create(); // 默认 v2
}
// 其余代码保持不变
// ...
}优点:
- 明确的迁移路径
- 不破坏任何现有代码
- V2 API 行为符合预期
方案 B: 渐进方案(推荐用于 major 版本)
在新的 major 版本(如 8.0.0)中:
- 将
PutExtra构造函数默认改为 v2 - 提供
PutExtra.createV1()供需要 v1 的用户使用 - 在 CHANGELOG 中明确标注为 BREAKING CHANGE
function PutExtra(...args) {
// ...
this.version = args[6] || 'v2'; // 改为默认 v2
}
PutExtra.createV1 = function(...args) {
return new PutExtra(...args, 'v1');
};
PutExtra.create = function(...args) {
return new PutExtra(...args, 'v2');
};🎯 当前 PR 的建议
鉴于这是一个 feature PR(从 PR 标题看),我建议:
-
修改
putFileV2的默认行为(按方案 A)- 当
putExtra为undefined/null时,使用PutExtra.create() - 这样 V2 API 默认使用 v2,符合用户预期
- 当
-
修改测试代码
- 在测试 V2 API 时,应该使用
PutExtra.create()或显式设置 version - 明确测试 v1 和 v2 的行为差异
- 在测试 V2 API 时,应该使用
-
更新 deprecation 警告
- 使警告信息更精确
- 考虑只在未指定 version 时才警告
-
在 PR 描述中明确说明兼容性
- 列出所有可能的 breaking changes
- 说明迁移路径
-
补充文档
- 更新 README 说明新旧 API 的区别
- 提供迁移示例
📝 其他发现的小问题
- Line 71, 111: JSDoc 中的空反引号
``应该填充为`resumeRecorder` 与 `resumeKey` - Example 文件:
examples/resume_upload_simple.js:18仍使用new PutExtra(),应改为展示新API的用法
总结
这个 PR 的核心设计(factory function + deprecation)是很好的,但在接口兼容性方面存在一个关键问题:
putFileV2不传putExtra时会使用 v2,这可能是 BREAKING CHANGE- 需要明确这是否是预期行为
- 如果是,需要在文档中明确说明
- 如果不是,需要按照上面的方案 A 修改
建议在合并前明确兼容性策略,并相应调整实现。
👉 Want me to re-run this review? Just type /review in the comments! For more usage examples, visit CodeAgent GitHub Repository.
Codecov Report❌ Patch coverage is
❌ Your project status has failed because the head coverage (23.45%) is below the target coverage (80.00%). You can increase the head coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## master #446 +/- ##
===========================================
- Coverage 86.14% 23.45% -62.70%
===========================================
Files 27 33 +6
Lines 2173 2294 +121
Branches 474 0 -474
===========================================
- Hits 1872 538 -1334
- Misses 301 1756 +1455
🚀 New features to boost your workflow:
|
No description provided.