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

Camunda Node.js外部任务OpenKM文件链接存流程变量为空问题

问题根因

变量值为空和encodeURIComponent没有任何关系,核心原因是Node.js异步执行时序错误:

  • exec是异步非阻塞方法,调用后不会等待curl请求执行完成、拿到OpenKM返回结果,代码会直接向下执行
  • 你执行processVariables.set("link", newlink)和taskService.complete时,exec的回调逻辑还没触发,newlink还是初始定义的空字符串,最终存入流程的变量值自然为空
  • 另外你代码里下载Camunda附件的逻辑也存在相同时序问题:发起http.get下载请求后,没等文件完全写入磁盘就执行上传,大概率会出现上传0字节损坏文件的问题。
修复方案

用Promise包装所有异步操作,配合async/await保证执行顺序,等上一步操作拿到结果后再走后续流程,修复后完整代码如下:

const { Client, logger } = require("camunda-external-task-client-js");
const { Variables } = require("camunda-external-task-client-js");
const { exec } = require('child_process');
const http = require('http');
const fs = require('fs');
// 未使用moment可删除该行及对应依赖
var moment = require("moment");

const config = { baseUrl: "http://localhost:8080/engine-rest" };
const client = new Client(config);

// 包装文件下载逻辑,等待文件写入完成再继续
function downloadFile(url, savePath) {
  return new Promise((resolve, reject) => {
    const file = fs.createWriteStream(savePath);
    http.get(url, (response) => {
      response.pipe(file);
      file.on("finish", () => {
        file.close();
        resolve();
      });
      file.on("error", (err) => {
        fs.unlink(savePath, () => {});
        reject(err);
      })
    }).on("error", reject);
  })
}

// 包装OpenKM上传逻辑,等待接口返回后生成访问链接
function uploadToOpenKM(cmd) {
  return new Promise((resolve, reject) => {
    exec(cmd, (err, stdout, stderr) => {
      if (err) {
        console.log("OpenKM上传错误: " + stderr);
        reject(err);
        return;
      }
      const res = JSON.parse(stdout);
      const accessLink = `http://172.20.16.90:8080/OpenKM/frontend/index.jsp?uuid=${res.uuid}`;
      resolve(accessLink);
    })
  })
}

client.subscribe("Rechnung", async function({ task, taskService }) {
  console.log("*** Processing task " + task.id);
  const uploadedFile = task.variables.get("rechnung");
  const tempSavePath = uploadedFile.filename;

  // 等待文件从Camunda下载完成、写入本地磁盘
  await downloadFile(`http://localhost:8080/engine-rest${uploadedFile.remotePath}`, tempSavePath);

  const uploadCmd = `curl -u okmAdmin:admin -H "Accept: application/json" -X POST -F docPath="/okm:root/manuel/${task.id}_${tempSavePath}" -F content="@${tempSavePath}" http://172.20.16.90:8080/OpenKM/services/rest/document/createSimple`;
  
  // 等待OpenKM上传完成,拿到生成的文件访问链接
  const finalLink = await uploadToOpenKM(uploadCmd);

  const processVariables = new Variables();
  processVariables.set("link", finalLink);

  await taskService.complete(task, processVariables);

  // 可选:任务完成后删除本地临时文件,避免磁盘空间占用
  fs.unlink(tempSavePath, () => {});
});
额外优化建议
  • 可以给异步逻辑加try/catch异常捕获,出现下载/上传失败时标记任务失败或者抛出BPMN错误,避免外部任务长时间持锁
  • 不需要的依赖(比如示例中未使用的moment)及时删除,减少代码冗余

内容的提问来源于stack exchange,提问作者Asterisk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 01:42:28