Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

添加支持多 host 自动切换 & 补全测试 #505

Merged
merged 28 commits into from
May 14, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
实现优化
  • Loading branch information
yinxulai committed May 14, 2021
commit 2a1d9fcf5a508df7bbf7c7b495841fcaaf76991d
43 changes: 22 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

### 当前版本为 3.x,旧版本文档:[2.x](https://github.com/qiniu/js-sdk/tree/2.x)、[1.x](https://github.com/qiniu/js-sdk/tree/1.x)

### 2.x 升级到 3.x 的注意事项请参考[文档](https://github.com/qiniu/js-sdk/wiki/2.x-%E5%8D%87%E7%BA%A7%E5%88%B0-3.x-%E6%96%87%E6%A1%A3%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9)
### 2.x 升级到 3.x 的注意事项请参考 [文档](https://github.com/qiniu/js-sdk/wiki/2.x-%E5%8D%87%E7%BA%A7%E5%88%B0-3.x-%E6%96%87%E6%A1%A3%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9)

## 快速导航

Expand Down Expand Up @@ -38,7 +38,7 @@ Qiniu-JavaScript-SDK 为客户端 SDK,没有包含 `token` 生成实现,为
* [C/C++](https://developer.qiniu.com/kodo/sdk/cpp)
* [Objective-C](https://developer.qiniu.com/kodo/sdk/objc)

Qiniu-JavaScript-SDK 的示例 [Demo](http://jssdk-v2.demo.qiniu.io) 中的服务器端部分是基于[Node.js 服务器端 SDK](https://developer.qiniu.com/kodo/sdk/nodejs) 开发的。
Qiniu-JavaScript-SDK 的示例 [Demo](http://jssdk-v2.demo.qiniu.io) 中的服务器端部分是基于 [Node.js 服务器端 SDK](https://developer.qiniu.com/kodo/sdk/nodejs) 开发的。

* [JavaScript SDK 在线示例](http://jssdk-v2.demo.qiniu.io/)

Expand All @@ -64,12 +64,12 @@ Qiniu-JavaScript-SDK 的示例 [Demo](http://jssdk-v2.demo.qiniu.io) 中的服

## 准备

* 在使用 JS-SDK 之前,您必须先注册一个七牛帐号,并登录控制台获取一对有效的 `AccessKey` 和 `SecretKey`,您可以阅读[快速入门](https://developer.qiniu.com/kodo/manual/console-quickstart)[安全机制](https://developer.qiniu.com/kodo/manual/security#security) 以进一步了解如何正确使用和管理密钥 。
* 在使用 JS-SDK 之前,您必须先注册一个七牛帐号,并登录控制台获取一对有效的 `AccessKey` 和 `SecretKey`,您可以阅读 [快速入门](https://developer.qiniu.com/kodo/manual/console-quickstart)[安全机制](https://developer.qiniu.com/kodo/manual/security#security) 以进一步了解如何正确使用和管理密钥 。

* JS-SDK 依赖服务端颁发 `token`,可以通过以下二种方式实现:

* 利用[七牛服务端 SDK](https://developer.qiniu.com/sdk#sdk)构建后端服务
* 利用七牛底层 API 构建服务,详见七牛[上传策略](https://developer.qiniu.com/kodo/manual/put-policy)[上传凭证](https://developer.qiniu.com/kodo/manual/upload-token)
* 利用 [七牛服务端 SDK](https://developer.qiniu.com/sdk#sdk) 构建后端服务
* 利用七牛底层 API 构建服务,详见七牛 [上传策略](https://developer.qiniu.com/kodo/manual/put-policy)[上传凭证](https://developer.qiniu.com/kodo/manual/upload-token)

前端通过接口请求以获得 `token` 信息

Expand All @@ -89,7 +89,7 @@ Qiniu-JavaScript-SDK 的示例 [Demo](http://jssdk-v2.demo.qiniu.io) 中的服

* 使用 NPM 安装

NPM 的全称是 Node Package Manager,是一个[NodeJS](https://nodejs.org)包管理和分发工具,已经成为了非官方的发布 Node 模块(包)的标准。如果需要更详细的关于 NPM 的使用说明,您可以访问[NPM 官方网站](https://www.npmjs.com),或对应的[中文网站](http://www.npmjs.com.cn/)
NPM 的全称是 Node Package Manager,是一个 [NodeJS](https://nodejs.org) 包管理和分发工具,已经成为了非官方的发布 Node 模块(包)的标准。如果需要更详细的关于 NPM 的使用说明,您可以访问 [NPM 官方网站](https://www.npmjs.com),或对应的 [中文网站](http://www.npmjs.com.cn/)

```
npm install qiniu-js
Expand Down Expand Up @@ -173,12 +173,13 @@ qiniu.compressImage(file, options).then(data => {
* total.total: `number`,本次上传的总量控制信息,单位为字节,注意这里的 total 跟文件大小并不一致。
* total.percent: `number`,当前上传进度,范围:0~100。

* error: 上传错误后触发;自动重试本身并不会触发该错误,而当重试次数到达上限后则可以触发。当不是 xhr 请求错误时,会把当前错误产生原因直接抛出,诸如 JSON 解析异常等;当产生 xhr 请求错误时,参数 err 的类型为 `QiniuError`, 你可以通过 `error.type` 得知具体的错误类型,通过 `error.message` 获取错误的信息,对于请求错误,err 的类型为 `QiniuRequestError`(继承自`QiniuError`)。
* error: 上传错误后触发;自动重试本身并不会触发该错误,而当重试次数到达上限后则可以触发。当不是 xhr 请求错误时,会把当前错误产生原因直接抛出,诸如 JSON 解析异常等;当产生 xhr 请求错误时,参数 err 的类型为 `QiniuError`, 你可以通过 `error.name` 得知具体的错误类型,通过 `error.message` 获取错误的信息,对于请求错误,err 的类型为 `QiniuRequestError`(继承自`QiniuError`)。
lzfee0227 marked this conversation as resolved.
Show resolved Hide resolved
* `QiniuRequestError` 拥有额外的信息:
* err.reqId: `string`,xhr 请求错误的 `X-Reqid`。
* err.code: `number`,请求错误状态码,可查阅码值对应[说明](https://developer.qiniu.com/kodo/api/3928/error-responses)。
* err.code: `number`,请求错误状态码,可查阅码值对应 [说明](https://developer.qiniu.com/kodo/api/3928/error-responses)。
* err.isRequestError: 用于区分是否为 xhr 请求错误;当 xhr 请求出现错误并且后端通过 HTTP 状态码返回了错误信息时,该参数为 `true`;否则为 `undefined` 。

* complete: 接收上传完成后的后端返回信息,具体返回结构取决于后端sdk的配置,可参考[上传策略](https://developer.qiniu.com/kodo/manual/1206/put-policy)。
* complete: 接收上传完成后的后端返回信息,具体返回结构取决于后端sdk的配置,可参考 [上传策略](https://developer.qiniu.com/kodo/manual/1206/put-policy)。

* subscription: 为一个带有 `unsubscribe` 方法的类实例,通过调用 `subscription.unsubscribe()` 停止当前文件上传。

Expand All @@ -197,7 +198,7 @@ qiniu.compressImage(file, options).then(data => {

* config.useCdnDomain: 表示是否使用 cdn 加速域名,为布尔值,`true` 表示使用,默认为 `false`。
* config.disableStatisticsReport: 是否禁用日志报告,为布尔值,默认为 `false`。
* config.uphost: 上传 `host`,类型为 `string[] | string`, 使用 `string[]` 时,内部会在重试过程中自动尝试不同的 `host`,如果设定该参数则优先使用该参数作为上传地址,默认为 `[]`。
* config.uphost: 上传 `host`,类型为 `string[] | string`,如果设定该参数则优先使用该参数作为上传地址,默认为 `[]`,传入多个 `host` 时,内部会在重试过程中根据情况自动切换不同的 `host`。
lzfee0227 marked this conversation as resolved.
Show resolved Hide resolved
* config.upprotocol: 自定义上传域名协议,值为 `https` 或者 `http`,默认为 `https`。
* config.region: 选择上传域名区域;当为 `null` 或 `undefined` 时,自动分析上传域名区域。
lzfee0227 marked this conversation as resolved.
Show resolved Hide resolved
* config.retryCount: 上传自动重试次数(整体重试次数,而不是某个分片的重试次数);默认 3 次(即上传失败后最多重试两次)。
Expand All @@ -219,7 +220,7 @@ qiniu.compressImage(file, options).then(data => {
```

* fname: `string`,文件原始文件名,若未指定,则魔法变量中无法使用 fname、ext、suffix
* customVars: `object`,用来放置自定义变量,变量名必须以 `x:` 开始,自定义变量格式及说明请参考[文档](https://developer.qiniu.com/kodo/manual/1235/vars)
* customVars: `object`,用来放置自定义变量,变量名必须以 `x:` 开始,自定义变量格式及说明请参考 [文档](https://developer.qiniu.com/kodo/manual/1235/vars)
* metadata: `object`,用来防止自定义 meta,变量名必须以 `x-qn-meta-`开始,自定义资源信息格式及说明请参考
[文档](https://developer.qiniu.com/kodo/api/1252/chgm)
* mimeType: `string`,指定所传的文件类型
Expand Down Expand Up @@ -292,7 +293,7 @@ qiniu.compressImage(file, options).then(data => {
mode: 1, // 图片水印
image: 'http://www.b1.qiniudn.com/images/logo-2.png', // 图片水印的Url,mode = 1 时 **必需**
dissolve: 50, // 透明度,取值范围1-100,非必需,下同
gravity: 'SouthWest', // 水印位置,为以下参数[NorthWest、North、NorthEast、West、Center、East、SouthWest、South、SouthEast]之一
gravity: 'SouthWest', // 水印位置,为以下参数 [NorthWest、North、NorthEast、West、Center、East、SouthWest、South、SouthEast] 之一
dx: 100, // 横轴边距,单位:像素(px)
dy: 100 // 纵轴边距,单位:像素(px)
}, key, domain)
Expand All @@ -318,23 +319,23 @@ qiniu.compressImage(file, options).then(data => {
}, key, domain)
```

options包含的具体水印参数解释见[水印(watermark)](https://developer.qiniu.com/dora/api/image-watermarking-processing-watermark)
options包含的具体水印参数解释见 [水印(watermark)](https://developer.qiniu.com/dora/api/image-watermarking-processing-watermark)

### qiniu.imageView2(options: object, key?: string, domain?: string): string (缩略)

返回处理后的图片url

```JavaScript
const imgLink = qiniu.imageView2({
mode: 3, // 缩略模式,共6种[0-5]
mode: 3, // 缩略模式,共 6 种 [0-5]
w: 100, // 具体含义由缩略模式决定
h: 100, // 具体含义由缩略模式决定
q: 100, // 新图的图像质量,取值范围:1-100
format: 'png' // 新图的输出格式,取值范围:jpg,gif,png,webp等
format: 'png' // 新图的输出格式,取值范围:jpg,gif,png,webp 等
}, key, domain)
```

options包含的具体缩略参数解释见[图片基本处理(imageView2)](https://developer.qiniu.com/dora/api/basic-processing-images-imageview2)
options包含的具体缩略参数解释见 [图片基本处理(imageView2)](https://developer.qiniu.com/dora/api/basic-processing-images-imageview2)

### qiniu.imageMogr2(options: object, key?: string, domain?: string): string (图像高级处理)

Expand All @@ -354,23 +355,23 @@ qiniu.compressImage(file, options).then(data => {
}, key, domain)
```

options包含的具体高级图像处理参数解释见[图像高级处理(imageMogr2)](https://developer.qiniu.com/dora/api/the-advanced-treatment-of-images-imagemogr2)
options包含的具体高级图像处理参数解释见 [图像高级处理(imageMogr2)](https://developer.qiniu.com/dora/api/the-advanced-treatment-of-images-imagemogr2)

### qiniu.imageInfo(key: string, domain: string): Promise

```JavaScript
qiniu.imageInfo(key, domain).then(res => {})
```

具体 imageInfo 解释见[图片基本信息(imageInfo)](https://developer.qiniu.com/dora/api/pictures-basic-information-imageinfo)
具体 imageInfo 解释见 [图片基本信息(imageInfo)](https://developer.qiniu.com/dora/api/pictures-basic-information-imageinfo)

### qiniu.exif(key: string, domain: string): Promise

```JavaScript
qiniu.exif(key, domain).then(res => {})
```

具体 exif 解释见[图片 EXIF 信息(exif)](https://developer.qiniu.com/dora/api/photo-exif-information-exif)
具体 exif 解释见 [图片 EXIF 信息(exif)](https://developer.qiniu.com/dora/api/photo-exif-information-exif)

### qiniu.pipeline(fopArr: array, key?: string, domain?: string): string

Expand Down Expand Up @@ -435,7 +436,7 @@ qiniu.compressImage(file, options).then(data => {
const imgLink = qiniu.pipeline(fopArr, key, domain))
```

fopArr包含的具体管道操作解释见[管道操作](https://developer.qiniu.com/dora/manual/processing-mechanism)
fopArr包含的具体管道操作解释见 [管道操作](https://developer.qiniu.com/dora/manual/processing-mechanism)

<a id="demo"></a>

Expand Down Expand Up @@ -467,7 +468,7 @@ qiniu.compressImage(file, options).then(data => {

2. 如果您想了解更多七牛的图片处理,建议您仔细阅读 [七牛官方文档-图片处理](https://developer.qiniu.com/dora/api/image-processing-api)

3. JS-SDK 示例生成 `token` 时,指定的 `Bucket Name` 为公开空间,所以可以公开访问上传成功后的资源。若您生成 `token` 时,指定的 `Bucket Name` 为私有空间,那您还需要在服务端进行额外的处理才能访问您上传的资源。具体参见[下载凭证](https://developer.qiniu.com/kodo/manual/download-token)。JS-SDK 数据处理部分功能不适用于私有空间。
3. JS-SDK 示例生成 `token` 时,指定的 `Bucket Name` 为公开空间,所以可以公开访问上传成功后的资源。若您生成 `token` 时,指定的 `Bucket Name` 为私有空间,那您还需要在服务端进行额外的处理才能访问您上传的资源。具体参见 [下载凭证](https://developer.qiniu.com/kodo/manual/download-token)。JS-SDK 数据处理部分功能不适用于私有空间。

<a id="faq"></a>

Expand Down
16 changes: 8 additions & 8 deletions src/api/index.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ import { QiniuRequestError } from '../errors'
import * as api from '.'
yinxulai marked this conversation as resolved.
Show resolved Hide resolved

export const errorMap = {
invalidRequest: new QiniuRequestError(0, 'mock'), // 请求错误
networkError: new QiniuRequestError(0, 'mock', 'message'), // 网络错误

invalidParams: new QiniuRequestError(400, 'mock'), // 无效的参数
expiredToken: new QiniuRequestError(401, 'mock'), // token 过期
invalidParams: new QiniuRequestError(400, 'mock', 'message'), // 无效的参数
expiredToken: new QiniuRequestError(401, 'mock', 'message'), // token 过期

gatewayUnavailable: new QiniuRequestError(502, 'mock'), // 网关不可用
serviceUnavailable: new QiniuRequestError(503, 'mock'), // 服务不可用
serviceTimeout: new QiniuRequestError(504, 'mock'), // 服务超时
serviceError: new QiniuRequestError(599, 'mock'), // 服务错误
gatewayUnavailable: new QiniuRequestError(502, 'mock', 'message'), // 网关不可用
serviceUnavailable: new QiniuRequestError(503, 'mock', 'message'), // 服务不可用
serviceTimeout: new QiniuRequestError(504, 'mock', 'message'), // 服务超时
serviceError: new QiniuRequestError(599, 'mock', 'message'), // 服务错误

invalidUploadId: new QiniuRequestError(612, 'mock'), // 无效的 upload id
invalidUploadId: new QiniuRequestError(612, 'mock', 'message'), // 无效的 upload id
}

export type ApiName =
Expand Down
11 changes: 11 additions & 0 deletions src/api/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { region } from '../config'
import { getUploadUrl } from '.'

jest.mock('../utils', () => ({
...jest.requireActual('../utils') as any,

request: () => Promise.resolve({
data: {
up: {
Expand Down Expand Up @@ -51,6 +53,15 @@ describe('api function test', () => {
url = await getUploadUrl(config, token)
expect(url).toBe('http://upload.qiniup.com')

config.upprotocol = 'https:'
url = await getUploadUrl(config, token)
expect(url).toBe('https://upload.qiniup.com')

config.upprotocol = 'http:'
url = await getUploadUrl(config, token)
expect(url).toBe('http://upload.qiniup.com')


config.uphost = 'qiniu.com'
url = await getUploadUrl(config, token)
expect(url).toBe('http://qiniu.com')
Expand Down
14 changes: 6 additions & 8 deletions src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { stringify } from 'querystring'

import { normalizeUploadConfig } from '../utils'
import { Config, UploadInfo } from '../upload'
import { regionUphostMap } from '../config'
import * as utils from '../utils'
Expand Down Expand Up @@ -157,16 +158,13 @@ export function direct(
* @param {string} token
* @returns Promise
* @description 获取上传 url
* @deprecated 将会在下一个大版本中移除
*/
export async function getUploadUrl(config: UploadUrlConfig, token: string): Promise<string> {
const protocol = config.upprotocol || 'https'
export async function getUploadUrl(_config: UploadUrlConfig, token: string): Promise<string> {
const config = normalizeUploadConfig(_config)
const protocol = config.upprotocol

if (config.uphost) {
if (Array.isArray(config.uphost)) {
return `${protocol}://${config.uphost[0]}`
}
return `${protocol}://${config.uphost}`
if (config.uphost.length > 0) {
return `${protocol}://${config.uphost[0]}`
}

if (config.region) {
lzfee0227 marked this conversation as resolved.
Show resolved Hide resolved
lzfee0227 marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
35 changes: 18 additions & 17 deletions src/errors/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export enum QiniuErrorType {
export enum QiniuErrorName {
// 输入错误
InvalidFile = 'InvalidFile',
InvalidToken = 'InvalidToken',
Expand All @@ -24,27 +24,28 @@ export enum QiniuErrorType {
InvalidProgressEventTarget = 'InvalidProgressEventTarget',

// 请求错误
RequestError = 'RequestError'
}
RequestError = 'RequestError',

export class QiniuError extends Error {
constructor(public type: QiniuErrorType, message?: string) {
super(message)
}
// 网络错误
NetworkError = 'NetworkError'
}

export function isQiniuError(error: any): error is QiniuRequestError {
if (error != null && QiniuErrorType[error.type] != null) return true
return false
export class QiniuError implements Error {
public stack: string | undefined
constructor(public name: QiniuErrorName, public message: string) {
this.stack = new Error().stack
}
}

export class QiniuRequestError extends QiniuError {
constructor(public code: number, public reqId: string, message?: string) {
super(QiniuErrorType.RequestError, message)
}
}

export function isQiniuRequestError(error: any): error is QiniuRequestError {
if (isQiniuError(error) && error.type === QiniuErrorType.RequestError) return true
return false
/**
* @description 标志当前的 error 类型是一个 RequestError
* @deprecated 下一个大版本将会移除
*/
public isRequestError = true

constructor(public code: number, public reqId: string, message: string) {
super(QiniuErrorName.RequestError, message)
}
}
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export { imageMogr2, watermark, imageInfo, exif, pipeline } from './image'
export { QiniuErrorName, QiniuError, QiniuRequestError } from './errors'
lzfee0227 marked this conversation as resolved.
Show resolved Hide resolved
export { deleteUploadedChunks, getUploadUrl } from './api'
export { default as upload } from './upload'
export { region } from './config'
export * from './errors'

export {
compressImage,
Expand Down
2 changes: 1 addition & 1 deletion src/logger/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export default class Logger {
) { }

private getPrintPrefix(level: LogLevel) {
return `Qiniu-JS-SDK [${level}][${this.prefix}#${this.id}]: `
return `Qiniu-JS-SDK [${level}][${this.prefix}#${this.id}]:`
}

/**
Expand Down
Loading