qiniu / nodejs-sdk

Qiniu Resource (Cloud) Storage SDK for Node.js
586 stars 190 forks source link

在egg中使用Promise始终返回404 #420

Closed A-birdFlyHigner closed 8 months ago

A-birdFlyHigner commented 8 months ago

1、在使用qiniu SDK 拉取文件时,始终返回404,考虑异步回调的原因,也加了Promise包裹,但是结果并不如意:

image

Reproduction Repo

bug.zip

始终返回:

image
lihsai0 commented 8 months ago

@A-birdFlyHigner 未能复现。

您提供的 zip 没有包含七牛的代码。

以下是基于您的 zip 修改,可正常工作的代码。

  1. 安装 qiniu 包,例如 npm install qiniu
  2. 修改 home.js

    const qiniu = require('qiniu');
    const { Controller } = require('egg');
    
    // 仅作演示,请根据实际需求选择合适的位置获取 bucketManager
    const accessKey = process.env.QINIU_ACCESS_KEY;
    const secretKey = process.env.QINIU_SECRET_KEY;
    const bucketName = process.env.QINIU_TEST_BUCKET;
    const mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
    const config = new qiniu.conf.Config();
    const bucketManager = new qiniu.rs.BucketManager(mac, config);
    
    // ....
    class HomeController extends Controller {
    // ...
    async list() {
      const { ctx } = this;
      const options = {
        limit: 10,
        prefix: '123/',
      };
      return new Promise((resolve, reject) => {
        bucketManager.listPrefix(bucketName, options, (err, respBody, respInfo) => {
          if (err) {
            reject(err);
            return;
          }
          console.log(respInfo);
    
          if (respInfo.statusCode !== 200) {
            ctx.throw(500, 'Internal Server Error');
            reject(new Error(`status: ${respInfo.statusCode}`));
            return;
          }
          console.log(respBody.items);
          ctx.body = {
            data: respBody.items,
          }
          resolve();
        });
      });
    }
    }
  3. 修改 router.js
    router.get('/list', controller.home.list); // 新增
  4. npm run dev
  5. 在浏览器访问对应地址

运行结果:

image

既然已经使用 aync 函数,建议包装 Promise 时使用 await 操作:

async list() {
  const { ctx } = this;
  const options = {
    limit: 10,
    prefix: '123/',
  };
  const {
    err,
    respBody,
    respInfo,
  } = await new Promise(resolve => {
    bucketManager.listPrefix(bucketName, options, (err, respBody, respInfo) => {
      resolve({ err, respBody, respInfo });
    });
  });
  if (err) {
    ctx.throw(500, new Error('internal err'));
    console.log(err, respInfo);
    return;
  }
  if (!respInfo || respInfo.statusCode !== 200) {
    ctx.throw(500, new Error('internal err'));
    console.log(err, respInfo);
    return;
  }
  ctx.body = {
    data: respBody.items,
  };
}

若您有更多问题,请继续评论。另外,请考虑您是否使用了代理,导致域名解析到了错误的 IP 地址。

A-birdFlyHigner commented 8 months ago

@A-birdFlyHigner 未能复现。

您提供的 zip 没有包含七牛的代码。

以下是基于您的 zip 修改,可正常工作的代码。

  1. 安装 qiniu 包,例如 npm install qiniu
  2. 修改 home.js
const qiniu = require('qiniu');
const { Controller } = require('egg');

// 仅作演示,请根据实际需求选择合适的位置获取 bucketManager
const accessKey = process.env.QINIU_ACCESS_KEY;
const secretKey = process.env.QINIU_SECRET_KEY;
const bucketName = process.env.QINIU_TEST_BUCKET;
const mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
const config = new qiniu.conf.Config();
const bucketManager = new qiniu.rs.BucketManager(mac, config);

// ....
class HomeController extends Controller {
// ...
  async list() {
    const { ctx } = this;
    const options = {
      limit: 10,
      prefix: '123/',
    };
    return new Promise((resolve, reject) => {
      bucketManager.listPrefix(bucketName, options, (err, respBody, respInfo) => {
        if (err) {
          reject(err);
          return;
        }
        console.log(respInfo);

        if (respInfo.statusCode !== 200) {
          ctx.throw(500, 'Internal Server Error');
          reject(new Error(`status: ${respInfo.statusCode}`));
          return;
        }
        console.log(respBody.items);
        ctx.body = {
          data: respBody.items,
        }
        resolve();
      });
    });
  }
}
  1. 修改 router.js
router.get('/list', controller.home.list); // 新增
  1. npm run dev
  2. 在浏览器访问对应地址

运行结果:

image

既然已经使用 aync 函数,建议包装 Promise 时使用 await 操作:

async list() {
  const { ctx } = this;
  const options = {
    limit: 10,
    prefix: '123/',
  };
  const {
    err,
    respBody,
    respInfo,
  } = await new Promise(resolve => {
    bucketManager.listPrefix(bucketName, options, (err, respBody, respInfo) => {
      resolve({ err, respBody, respInfo });
    });
  });
  if (err) {
    ctx.throw(500, new Error('internal err'));
    console.log(err, respInfo);
    return;
  }
  if (!respInfo || respInfo.statusCode !== 200) {
    ctx.throw(500, new Error('internal err'));
    console.log(err, respInfo);
    return;
  }
  ctx.body = {
    data: respBody.items,
  };
}

若您有更多问题,请继续评论。另外,请考虑您是否使用了代理,导致域名解析到了错误的 IP 地址。

这有个测试仓库 https://github.com/A-birdFlyHigner/test-egg

lihsai0 commented 8 months ago

@A-birdFlyHigner 这个 404 是您的 notFoundHandler 中间件没拿到 ctx.body 返回的,与七牛无关。您的代码没有设置 ctx.body 请按以下步骤修改您的业务逻辑:

请参考上面的代码修改 QiniuServicegetFileListByBucketAndPrefix 使其返回文件列表。

修改 QiniuControllergetFileListByBucketAndPrefix 使其为 async 函数,并通过 await 获取 QiniuServicegetFileListByBucketAndPrefix 的结果。最后将结果写入到 ctx.body 中。

A-birdFlyHigner commented 8 months ago

@A-birdFlyHigner 这个 404 是您的 notFoundHandler 中间件没拿到 ctx.body 返回的,与七牛无关。您的代码没有设置 ctx.body 请按以下步骤修改您的业务逻辑:

请参考上面的代码修改 QiniuServicegetFileListByBucketAndPrefix 使其返回文件列表。

修改 QiniuControllergetFileListByBucketAndPrefix 使其为 async 函数,并通过 await 获取 QiniuServicegetFileListByBucketAndPrefix 的结果。最后将结果写入到 ctx.body 中。

其实在listPrefix的回调里面,已经和返回给我404了。我在Controller里面已经await了,建议的写法依旧不行

image
lihsai0 commented 8 months ago

@A-birdFlyHigner 您红框打印的是 ctx.body,而 ctx.body 此时还未赋值,当然没有内容。您截图代码七牛返回的信息在 err, respBody, respInfo 这三个变量中。

A-birdFlyHigner commented 8 months ago

@A-birdFlyHigner 您红框打印的是 ctx.body,而 ctx.body 此时还未赋值,当然没有内容。您截图代码七牛返回的信息在 err, respBody, respInfo 这三个变量中。

但是实际上已经触发了notFoundHandler这个中间件,并且已经给我赋值并返回过了。。你们有没有提供 promise 的 api: image image

lihsai0 commented 8 months ago

@A-birdFlyHigner Promise 风格的 API 是计划要做的,暂时还没有,十分抱歉。 试了一下,上面提供的封装方式在中间件下,也可以正常工作。应该是您自己的代码问题,请自行排查一下。

A-birdFlyHigner commented 8 months ago

@A-birdFlyHigner Promise 风格的 API 是计划要做的,暂时还没有,十分抱歉。 试了一下,上面提供的封装方式在中间件下,也可以正常工作。应该是您自己的代码问题,请自行排查一下。

吐。。。。到最后发现是jwt中间件没有await next() = =

image

感谢耐心解答