npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@winman-f2e/nos-js-web

v1.0.1

Published

浏览器上使用的nos直传

Downloads

179

Readme

@winman-f2e/nos-js-web

浏览器上使用的nos直传

安装

npm i @winman-f2e/nos-js-web

快速开始

第一步 创建一个通用上传配置

比如shared/nos-uploader

import {
  NOSWebClass,
  NOSDefaultUploader
} from '@winman-f2e/nos-js-web';

const NOSUploader = new NOSWebClass(NOSDefaultUploader);
// NOSDefaultUploader 是使用的上传方式
// 有以下3种方式可供选择
// - NOSDefaultUploader - 默认上传方式,单请求上传整个文件
// - NOSBlockUploader - NOS分块直传,串行上传
// - NOSConcurrentUploader - 并行分块直传

NOSUploader.useGetToken((uploader) => {
  const file = uploader._originFile;
  return fetch(
    // 这是业务接口的内容,可以查看nos直传文档(https://sf.163.com/help/documents/67031136644288512)了解接口内容
    '/genUploadToken'
  ).then(({ response }) => {
      const data = await response.json();
      return {
        objectKey: data.objectName, // NOS 对象名
        bucketName: data.bucketName, // NOS 桶名
        token: data.uploadToken // NOS 直传凭证: https://sf.163.com/help/documents/67031136644288512
      }
    })
})

export NOSUploader;

第二步 开始上传

比如在react中使用

import React, {
  useCallback
} from 'react'
import { NOSUploader } from './shared/nos-uploader';

const Uploader = () => {
  const uploadFile = useCallback((file) => {
    const task = NOSUploader.createUploadTask(file);
    // 监听上传进度
    task.addListener('progress', () => {
      // 上传中信息,详细内容可查看【#task.uploadInfo 上传中进度信息】
      /**
      {
        percent: number,
        timestamp: number,
        sent?: number,
        total?: number
      }
      **/
      task.uploadInfo
    );
    // 监听上传完成
    task.addListener('complete', () => {
      task.uploadedInfo
    });
    // 监听上传错误
    task.addListener('error', () => {});

    // 开始上传
    task.upload();
  }, []);
  return (
    <div>
      <button
        type="file"
        onClick={(event) => {
          uploadFile(event.target.files[0])
        }}
      ></button>
    </div>
  )
}

总共2步,第二步是可以在任意业务场景中使用的。

常见问题

FAQ

写在前面的几个概念

NOSClass 平台适配类

  • NOSClass
  • NOSWebClass

Uploader 上传行为

  • NOSDefaultUploader - 默认上传方式,单请求上传整个文件
  • NOSBlockUploader - NOS分块直传,串行上传
  • NOSConcurrentUploader - 并行分块直传

upload 上传实例

const upload = new NOSWebClass(
  NOSConcurrentUploader // NOSDefaultUploader或NOSBlockUploader或NOSConcurrentUploader
)

这句表示,用浏览器支持的方式构建一个并行分块上传

task 一个具体的文件上传任务

const task = upload.createUploadTask(file)

task的属性

task.uploadInfo 上传中进度信息
export interface UploadInfo {
  /**
   * 上传进度 0-1
   */
  percent: number,
  /**
   * 上次更新的时间戳
   */
  timestamp: number,
  /**
   * 已发送的文件大小
   */
  sent?: number,
  /**
   * 文件总大小
   */
  total?: number
}
task.uploadedInfo 上传完成后的nos数据
/**
 * UploadedInfo 上传完成后的nos数据
 */
export interface UploadedInfo {
  objectKey: string,
  bucketName: string
}

task的函数

task.upload()

开始上传

task.pause()

暂停上传,暂停后调用task.upload会继续上传

task.abort()

取消上传,进度清零

task.destroy()

销毁,会取消上传,并移除所有事件

task.addListener|task.removeListener

添加和移除事件,可以查看task的事件

task的事件

可以通过

const callback = () => {};
// 添加监听事件
task.addListener('事件名字', callback);
// 移除监听事件
task.removeListener('事件名字', callback);

// 移除所有该事件名上的监听
task.removeListener('事件名字');
// 移除该函数绑定的所有事件
task.removeListener(callback);
progress

上传进度事件

complete

上传完成事件

error

上传错误事件

import {
  ERROR_CODE_MAP
} from '@winman-f2e/nos-js-web';

task.addListener('error', (event) => {
  const error = event.data;
  if (error.code === ERROR_CODE_MAP.CONCURRENT_GET_BLOCK_MD5_FAIL.code) {
    // concurrentUploader获取分片md5失败
  }
});

ERROR_CODE_MAP说明:

|key|错误说明|code|message| |---|---|---|---| |GET_TOKEN_FAIL|获取token失败|100|get NOS token fail| |DEFAULT_UPLOAD_FAIL|defaultUploader上传失败|1000|| |BLOCK_RETRIES_EXCEEDED|blockUploader重试过多,上传失败|2000|upload error: retries have exceeded the limit.| |BLOCK_FETCH_OFFSET_FAIL|blockUploader获取上次上传进度失败|2001|| |CONCURRENT_GET_UPLOAD_ID_FAIL|concurrentUploader获取uploadId失败|3000|| |CONCURRENT_GET_BLOCK_MD5_FAIL|concurrentUploader获取分片md5失败|3001|| |CONCURRENT_GET_COMPLETE_ALL_BLOCKS_FAIL|concurrentUploader分片完成后,合并分片失败|3002|| |CONCURRENT_RETRIES_EXCEEDED|concurrentUploader重试次数过多|3003||

更多使用方法

定义自己的业务 NOS token 获取方式

1. 实例化后注入

import {
  NOSWebClass,
  NOSDefaultUploader
} from '@winman-f2e/nos-js-web';

const upload = new NOSWebClass(NOSDefaultUploader);

upload.useGetToken((uploader) => {
  const file = uploader._originFile;
  return fetch(
    '/genUploadToken'
  ).then(({ response }) => {
      const data = await response.json();
      return {
        objectKey: data.objectName, // NOS 对象名
        bucketName: data.bucketName, // NOS 桶名
        token: data.uploadToken // NOS 直传凭证: https://sf.163.com/help/documents/67031136644288512
      }
    })
})

2. 创建新类

class CustomNOSClass extends NOSWebClass {
  getNOSToken: (uploader) => Promise<{ objectKey: string, bucketName: string, token: string}>
}

当然也可以在实例化后在此之前动态修改

const customNOS = new CustomNOSClass(NOSDefaultUploader);

customNOS.useGetToken(() => {
  // ....
})

使用非nos.netease.com上传,如建德的NOS分区

如果我们申请的NOS桶分区不属于 nos.netease.com。如果属于建德的,那我们可以修改如下:

import {
  APIS
} from '@winman-f2e/nos-js';
import {
  NOSWebClass,
  NOSDefaultUploader
} from '@winman-f2e/nos-js-web';

const upload = new NOSWebClass(NOSDefaultUploader);

upload.updateAPI(APIS.jd);

当然也可以根据实际的需求进行变更。变更方法如下:

upload.updateAPI({
  NOS_UPLOAD: {
    url: 'https://{bucketName}.nos-jd.163yun.com',
    method: 'POST'
  },

  NOS_GET_OBJECT: {
    url: 'https://{bucketName}.nos-jd.163yun.com/{objectKey}',
  },

  NOS_BLOCK_UPLOAD: {
    url: 'https://{bucketName}.nos-jd.163yun.com/{objectKey}',
    method: 'POST'
  },

  // 获取上传进度
  FETCH_BLOCK_UPLOAD_CONTEXT: {
    url: 'https://{bucketName}.nos-jd.163yun.com{objectKey}',
    method: 'GET'
  },

  NOS_CONCURRENT_UPLOAD: {
    url: 'https://{bucketName}.nos-jd.163yun.com/{objectKey}'
  }
})

其中 {bucketName}{objectKey}useGetToken 返回数据的占位符,会自动替换

配置并行上传的分块大小

import {
  NOSWebClass,
  NOSConcurrentUploader
} from '@winman-f2e/nos-js-web';

class MyNOSConcurrentUploader extends NOSConcurrentUploader {
  blockSize = 1024 * 1024 * 10, // 默认:10MB
  shouldUpdateProgressFromBlockUploading = true // 设置是否在每个分块上传一部分也更新整体进度,关闭可以方式暂停的进度回退。但是需要配合设置一个blockSize,才能获得一个比较好的进度体验
}
const upload = new NOSWebClass(MyNOSConcurrentUploader);

自定义上传逻辑

比如我们需要再上传完成后,额外发送一个请求,校验文件信息,才能确认上传完成

import {
  NOSWebClass,
  NOSConcurrentUploader
 } from '@winman-f2e/nos-js-web';


export class CustomUploader extends NOSConcurrentUploader {
  public checkRemote = () => {
    return fetch(
      '/check',
      {
        method: 'GET',
        query: {
          objectName: this.signature?.key
        }
      }
    )
  }

  updateProgress (progressInfo) {
    // 未获取信息前,最大 99%;
    progressInfo.percent = Math.min(0.99, progressInfo.percent);
    super.updateProgress.call(this, progressInfo)
  }

  setComplete () {
    return this.checkRemote()
      .then(
        () => {
          super.setComplete.call(this)
        },
        () => {
          this.setError('文件校验有误')
        })
  }
}

// 使用 new NOSWebClass 进行实例化,即会可以在
const upload = new NOSWebClass(CustomUploader);

API

import {
  NOSClass,
  NOSUploader,
  NOSBlockUploader,
  NOSDefaultUploader,
  NOSConcurrentUploader,

  WebAdapter,
  NOSWebClass,
  NOSWeb,
  BlockNOSWeb,
  ConcurrentNOSWeb
} from '@winman-f2e/nos-js-web';

来自 @winman-f2e/nos-js

参考 @winman-f2e/nos-js API

  • NOSClass
  • NOSUploader
  • NOSBlockUploader
  • NOSDefaultUploader
  • NOSConcurrentUploader

特有API

WebAdapter 和 NOSWebClass

  • WebAdapter 是浏览器端的适配器工具实现的集合
  • NOSWebClass 是 WebAdapter 装配到 NOSClass 后的产物

一般直接使用NOSWebClass即可,如:

const upload = new NOSWebClass(CustomUploader);

即可完成浏览器端自定义上传器。

NOSWeb

export const NOSWeb = new NOSWebClass(NOSDefaultUploader);

使用方法:基础使用例子

BlockNOSWeb

使用方法同NOSWeb

export const BlockNOSWeb = new NOSWebClass(NOSBlockUploader);

ConcurrentNOSWeb

使用方法同NOSWeb

export const ConcurrentNOSWeb = new NOSWebClass(NOSConcurrentUploader);

RichMediaURL 富媒体url处理工具

@winman-f2e/nos-js#richmediaurl-富媒体url处理工具 直接从 @winman-f2e/nos-js 包中导出