Skip to content

@alicloud/bailian20230601 包在next.js14的框架中,进行流式数据请求之前获取token的时候会进行报错 #22

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

Closed
buzhou9 opened this issue Jan 26, 2024 · 1 comment

Comments

@buzhou9
Copy link

buzhou9 commented Jan 26, 2024

这是用于测试的路由文件代码

// 文件路径 app/api/test-stream/route.ts

import aliTokenHandler from "@/utils/aliTokenHandler";
import {NextRequest, NextResponse} from 'next/server';

export const runtime = 'edge';

async function handler(request: NextRequest, res: NextResponse, token: string) {

  const responseStream = new TransformStream();
  const writer = responseStream.writable.getWriter();
  const encoder = new TextEncoder();

  try {
    const responseChunks = `This is a response from a NextJS server. Thank you for your message! ${token}`.split(' ');
    sendStream(writer, encoder, responseChunks);
  } catch (err) {
    console.log(JSON.stringify(err));
    throw err;
  }

  return new Response(responseStream.readable, {
    headers: {
      'Content-Type': 'text/event-stream',
      Connection: 'keep-alive',
      'Cache-Control': 'no-cache, no-transform',
    },
  });

  function sendStream(
    writer: WritableStreamDefaultWriter<any>,
    encoder: TextEncoder,
    responseChunks: string[],
    chunkIndex = 0
  ) {
    setTimeout(() => {
      const chunk = responseChunks[chunkIndex];
      if (chunk) {
        // Sends response back to Deep Chat using the Response format:
        // https://deepchat.dev/docs/connect/#Response
        writer.write(encoder.encode(`data: ${JSON.stringify({text: `${chunk} `})}\n\n`));
        sendStream(writer, encoder, responseChunks, chunkIndex + 1);
      } else {
        writer.close();
      }
    }, 70);
  }
}

const GET = aliTokenHandler(handler)

export {
  GET
}

这是aliTokenHandler封装的方法

// 文件路径 /utils/aliTokenHandler
import {NextRequest, NextResponse} from 'next/server';
import Client from '@alicloud/bailian20230601'
import * as memoryCache from 'memory-cache'

type CallbackFunc = (req: NextRequest, res: NextResponse, token: string) => Promise<NextResponse<Response>> | Promise<Response>;

async function getToken() {

  const cacheKey = 'bailian_token'

  if (memoryCache.get(cacheKey)) {
    return memoryCache.get(cacheKey)
  }

  const accessKeyId = process.env.ALY_ACCESS_KEY_ID || '';
  const accessKeySecret = process.env.ALY_ACCESS_KEY_SECRET || '';
  const agentKey = process.env.ALY_BAILIAN_AGENT_KEY || '';
  const endpoint = 'bailian.cn-beijing.aliyuncs.com'

  // @ts-ignore
  const c = new Client({
    accessKeyId: accessKeyId,
    accessKeySecret: accessKeySecret,
    endpoint: endpoint
  })

  async function createToken() {
    const response = await c.createToken(
      // @ts-ignore
      { agentKey: agentKey }
    );

    const responseBody = response.body
    if (responseBody === null) {
      throw new Error('failed to create token')
    }

    if (responseBody.success !== true) {
      let requestId = responseBody.requestId;
      if (requestId == null) {
        requestId = response.headers["x-acs-request-id"];
      }

      let error = "failed to create token " + responseBody.message + ", requestId: " + requestId;
      throw new Error(error)
    }

    const tokenData = responseBody.data
    if (!tokenData) {
      throw new Error("failed to create token");
    }
    return tokenData
  }

  try {
    const { token = '', expiredTime = 0} = await createToken()
    memoryCache.put(cacheKey, token, expiredTime * 1000 - new Date().getTime());
    console.log('token: ' + memoryCache.get(cacheKey) + ', expiredTime: ' + expiredTime);
    return token
  } catch (err) {
    console.error('failed to create token, err: ', err);
    throw err
  }
}

export default function errorHandler(callbackFunc: CallbackFunc) {
  return async (req: NextRequest, res: NextResponse) => {
    try {
      const token = await getToken()
      return await callbackFunc(req, res, token);
    } catch (error) {
      console.error('API Error:', error);
      // Sends response back to Deep Chat using the Response format:
      // https://deepchat.dev/docs/connect/#Response
      return NextResponse.json({error}, {status: 500});
    }
  };
}

执行步骤

在浏览器访问 http://localhost:3000/api/test-stream

预期结果

流式输出文本并且返回token

实际结果

报错,以下是控制台错误日志

 ○ Compiling /api/test-stream ...
 ⨯ ./node_modules/@alicloud/credentials/dist/src/oidc_role_arn_credential.js:9:29
Module not found: Can't resolve 'fs'

https://nextjs.org/docs/messages/module-not-found

Import trace for requested module:
./node_modules/@alicloud/credentials/dist/src/client.js
./node_modules/@alicloud/openapi-client/dist/client.js
./node_modules/@alicloud/bailian20230601/dist/client.js
./src/utils/aliTokenHandler.ts
./src/app/api/test-stream/route.ts
./node_modules/next/dist/build/webpack/loaders/next-edge-app-route-loader/index.js?absolutePagePath=%2FUsers%2Fhuangxiaotong%2Fwork%2Fpenglai%2Fsrc%2Fapp%2Fapi%2Ftest-stream%2Froute.ts&page=%2Fapi%2Ftest-stream%2Froute&appDirLoader=bmV4dC1hcHAtbG9hZGVyP25hbWU9YXBwJTJGYXBpJTJGdGVzdC1zdHJlYW0lMkZyb3V0ZSZwYWdlPSUyRmFwaSUyRnRlc3Qtc3RyZWFtJTJGcm91dGUmYXBwUGF0aHM9JnBhZ2VQYXRoPXByaXZhdGUtbmV4dC1hcHAtZGlyJTJGYXBpJTJGdGVzdC1zdHJlYW0lMkZyb3V0ZS50cyZhcHBEaXI9JTJGVXNlcnMlMkZodWFuZ3hpYW90b25nJTJGd29yayUyRnBlbmdsYWklMkZzcmMlMkZhcHAmcGFnZUV4dGVuc2lvbnM9dHN4JnBhZ2VFeHRlbnNpb25zPXRzJnBhZ2VFeHRlbnNpb25zPWpzeCZwYWdlRXh0ZW5zaW9ucz1qcyZyb290RGlyPSUyRlVzZXJzJTJGaHVhbmd4aWFvdG9uZyUyRndvcmslMkZwZW5nbGFpJmlzRGV2PXRydWUmdHNjb25maWdQYXRoPXRzY29uZmlnLmpzb24mYmFzZVBhdGg9JmFzc2V0UHJlZml4PSZuZXh0Q29uZmlnT3V0cHV0PSZwcmVmZXJyZWRSZWdpb249Jm1pZGRsZXdhcmVDb25maWc9ZTMwJTNEIQ%3D%3D&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D!
 ⚠ ./node_modules/sax/lib/sax.js
Module not found: Can't resolve 'stream' in '/Users/huangxiaotong/work/penglai/node_modules/sax/lib'

Import trace for requested module:
./node_modules/sax/lib/sax.js
./node_modules/xml2js/lib/parser.js
./node_modules/xml2js/lib/xml2js.js
./node_modules/@alicloud/tea-xml/dist/client.js
./node_modules/@alicloud/openapi-client/dist/client.js
./node_modules/@alicloud/bailian20230601/dist/client.js
./src/utils/aliTokenHandler.ts
./src/app/api/test-stream/route.ts
./node_modules/next/dist/build/webpack/loaders/next-app-loader.js?name=app%2Fapi%2Ftest-stream%2Froute&page=%2Fapi%2Ftest-stream%2Froute&appPaths=&pagePath=private-next-app-dir%2Fapi%2Ftest-stream%2Froute.ts&appDir=%2FUsers%2Fhuangxiaotong%2Fwork%2Fpenglai%2Fsrc%2Fapp&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&rootDir=%2FUsers%2Fhuangxiaotong%2Fwork%2Fpenglai&isDev=true&tsconfigPath=tsconfig.json&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D!./src/app/api/test-stream/route.ts?__next_edge_ssr_entry__
 ⚠ Fast Refresh had to perform a full reload due to a runtime error.

当我不使用流式返回的时候这个API工作是正常的

return NextResponse.json({text: `This is a respone from a NextJS edge server. Thankyou for your message! ${token}`});

我现在需要接入通义千问大模型的流式传输的接口,无法以这种形式去创建token

@buzhou9 buzhou9 closed this as completed Jan 26, 2024
@buzhou9
Copy link
Author

buzhou9 commented Jan 26, 2024

export const runtime = 'edge'; 

改为

export const config = {
  runtime: 'edge',
};

就成功了,不知道为什么

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant