You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

部署Node.js Azure Functions v4时引入@azure/cosmos导致函数处理器无法被识别的问题

部署Node.js Azure Functions v4时引入@azure/cosmos导致函数处理器无法被识别的问题

我之前也遇到过类似的依赖打包导致Azure Functions无法识别函数的问题,结合你的描述,这大概率是tsup的打包配置或者@azure/cosmos的依赖处理和Azure Functions运行时不兼容导致的,下面一步步来分析和解决:

问题回顾

你在部署Node.js Azure Functions v4应用时,只要引入并使用@azure/cosmos包,Azure运行时就无法检测到函数处理器;部署看似成功,但门户里函数列表为空,所有API请求返回404。注释掉@azure/cosmos的导入和使用后,一切正常。

环境信息

  • Azure Functions Runtime: v4
  • Node.js Version: v22.x
  • TypeScript Version: latest
  • Bundler: tsup v8.5.0
  • 核心依赖版本:@azure/functions: v4.7.3、@azure/cosmos: v4.4.1
  • 部署命令:func azure functionapp publish <app-name>

问题根源分析

核心问题出在tsup的打包配置和Azure Functions运行时的依赖加载逻辑不匹配:
你的tsup配置里把@azure/cosmos标记为了external(外部依赖),这意味着打包后的代码不会把@azure/cosmos的代码包含进去,而是保留导入语句,让运行时去node_modules里找这个包。但实际部署时会出现两个关键问题:

  1. Azure Functions部署过程中可能没有正确上传@azure/cosmos依赖到函数应用目录
  2. Node.js v22的ESM模块解析逻辑和@azure/cosmos的内部依赖结构存在兼容问题,导致运行时加载@azure/cosmos失败,进而整个函数入口文件执行中断,Azure Functions根本没机会完成函数注册

另外,你在代码里提前在函数定义之外实例化了CosmosClient,如果这个实例化过程因为依赖加载失败抛出异常,会直接终止入口文件的执行,彻底阻断函数的注册流程。

解决方案

方案1:调整tsup打包配置,将@azure/cosmos打包进产物

修改你的tsup.config.ts,把@azure/cosmos从external数组中移除,让tsup把它的代码直接打包到dist目录里,避免运行时依赖加载失败:

import { defineConfig } from 'tsup'
import alias from 'esbuild-plugin-alias'
import path from 'path'

export default defineConfig({
  entry: ['src/index.ts'],
  outDir: 'dist',
  format: 'esm',
  target: 'node22',
  splitting: false,
  sourcemap: false,
  dts: false,
  // 仅保留@azure/functions为外部依赖(Azure运行时会自动处理它的加载)
  external: ['@azure/functions'],
  clean: true,
  esbuildPlugins: [
    alias({
      '#common': path.resolve(__dirname, '../common/src'),
    }),
  ],
})

方案2:延迟CosmosClient的实例化(避免入口初始化失败)

即使调整了打包配置,也建议你不要在函数定义之外提前实例化CosmosClient,而是把实例化逻辑放在函数处理内部,这样即使依赖加载出问题,也只会在调用函数时报错,不会导致函数无法被Azure识别:

import { app } from "@azure/functions";
import { CosmosClient } from "@azure/cosmos";

// 仅定义配置,不提前实例化客户端
const COSMOS_DB_ENDPOINT = process.env.COSMOS_DB_ENDPOINT;
const COSMOS_DB_KEY = process.env.COSMOS_DB_KEY;
const COSMOS_DB_NAME = process.env.COSMOS_DB_DATABASE_ID;
const cosmosConfig = {
  endpoint: COSMOS_DB_ENDPOINT,
  key: COSMOS_DB_KEY,
  databaseId: COSMOS_DB_NAME,
  containers: { users: "Users" },
};

app.http("get-user-details", {
  methods: ["GET"],
  authLevel: "anonymous",
  route: "user/{userId}",
  handler: async (request) => {
    try {
      // 在函数执行时才实例化CosmosClient
      const cosmosClient = new CosmosClient({
        endpoint: cosmosConfig.endpoint,
        key: cosmosConfig.key,
        connectionPolicy: { enableEndpointDiscovery: true }
      });
      const container = cosmosClient.database(cosmosConfig.databaseId).container("Items");
      
      // 后续业务逻辑
      console.log(container);
      return {
        status: 200,
        jsonBody: { data: "validatedUserItem" }
      };
    } catch (error) {
      console.log("error: ", error);
      return {
        status: 500,
        jsonBody: { data: "error" }
      };
    }
  }
});

方案3:确保部署时正确上传node_modules(适合坚持外部依赖的场景)

如果你还是想把@azure/cosmos作为外部依赖,需要确保部署时把node_modules一起上传到Azure:

  1. 本地先执行npm install确保node_modules包含@azure/cosmos
  2. 使用func azure functionapp publish <app-name> --no-build命令部署,避免Azure在部署时重新构建导致依赖丢失
  3. 或者在Azure Portal的Function App配置中,设置SCM_DO_BUILD_DURING_DEPLOYMENT为true,让Azure在部署时自动安装依赖

验证步骤

  1. 按照上述任意方案调整配置或代码
  2. 重新执行npm run build完成打包
  3. 用func azure functionapp publish <app-name>部署应用
  4. 登录Azure Portal查看Function App的「Functions」标签,确认get-user-details触发器已被识别
  5. 调用.../api/user/{userId}端点,验证是否返回正常响应

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 11:28:00