Wexflow多语言客户端开发:C#、Python、Java等语言集成指南

【免费下载链接】wexflow Workflow Automation Engine 【免费下载链接】wexflow 项目地址: https://gitcode.com/gh_mirrors/we/wexflow

想要将Wexflow工作流自动化引擎集成到您的应用程序中吗?本指南将为您详细介绍如何通过REST API使用C#、Python、Java等多种编程语言开发Wexflow客户端,实现跨语言的工作流自动化集成。Wexflow作为一个强大的开源工作流引擎,提供了完善的RESTful API接口,让您可以轻松地在任何应用程序中触发和管理工作流。

📋 Wexflow REST API基础

Wexflow提供了完整的REST API接口,支持工作流的管理、执行和监控。所有API端点都位于/api/v1路径下,使用标准的HTTP方法进行操作。

核心API端点

以下是Wexflow的主要API端点:

  • 认证接口POST /api/v1/login - 获取访问令牌
  • 工作流启动POST /api/v1/start?w={workflowId} - 启动指定工作流
  • 工作流停止POST /api/v1/stop?w={workflowId}&i={instanceId} - 停止运行中的工作流
  • 工作流搜索GET /api/v1/search?s={keyword} - 搜索工作流
  • 工作流详情GET /api/v1/workflow?w={workflowId} - 获取工作流信息

Wexflow工作流自动化引擎

🚀 C#客户端开发指南

C#是Wexflow的原生开发语言,提供了最完整的客户端支持。您可以使用官方提供的Wexflow.Core.Service.Client库或直接调用REST API。

使用官方客户端库

Wexflow项目已经提供了完整的C#客户端实现,位于src/net/Wexflow.Core.Service.Client/WexflowServiceClient.cs。这个客户端封装了所有常用的API操作:

// 创建客户端实例
var client = new WexflowServiceClient("http://localhost:8000/api/v1");

// 登录获取令牌
string token = client.Login("admin", "wexflow2018");

// 搜索工作流
var workflows = client.Search("处理", token);

// 启动工作流
Guid instanceId = client.StartWorkflow(41, token);

// 停止工作流
client.StopWorkflow(41, instanceId, token);

直接调用REST API

如果您需要更灵活的控制,可以直接使用HttpClient调用API:

using System.Net.Http;
using Newtonsoft.Json;

public async Task<string> StartWorkflowAsync(int workflowId, string token)
{
    using var client = new HttpClient();
    client.DefaultRequestHeaders.Authorization = 
        new AuthenticationHeaderValue("Bearer", token);
    
    var response = await client.PostAsync(
        $"http://localhost:8000/api/v1/start?w={workflowId}", 
        null);
    
    return await response.Content.ReadAsStringAsync();
}

🐍 Python客户端开发指南

Python开发者可以通过简单的HTTP请求与Wexflow集成。项目提供了完整的Python客户端示例samples/clients/client/client.py

基本Python客户端实现

import requests

class WexflowClient:
    def __init__(self, base_url="http://localhost:8000/api/v1"):
        self.base_url = base_url
        self.token = None
    
    def login(self, username, password):
        """登录获取访问令牌"""
        url = f"{self.base_url}/login"
        payload = {
            "username": username,
            "password": password,
            "stayConnected": False
        }
        
        response = requests.post(url, json=payload)
        response.raise_for_status()
        
        self.token = response.json()["access_token"]
        return self.token
    
    def start_workflow(self, workflow_id):
        """启动工作流"""
        if not self.token:
            raise ValueError("请先登录")
        
        url = f"{self.base_url}/start?w={workflow_id}"
        headers = {"Authorization": f"Bearer {self.token}"}
        
        response = requests.post(url, headers=headers)
        response.raise_for_status()
        
        return response.json()
    
    def search_workflows(self, keyword):
        """搜索工作流"""
        if not self.token:
            raise ValueError("请先登录")
        
        url = f"{self.base_url}/search?s={keyword}"
        headers = {"Authorization": f"Bearer {self.token}"}
        
        response = requests.get(url, headers=headers)
        response.raise_for_status()
        
        return response.json()

使用示例

# 创建客户端
client = WexflowClient()

# 登录
token = client.login("admin", "wexflow2018")

# 启动工作流
job_id = client.start_workflow(41)
print(f"工作流已启动,作业ID: {job_id}")

# 搜索工作流
workflows = client.search_workflows("图片处理")
for workflow in workflows:
    print(f"找到工作流: {workflow['name']} (ID: {workflow['id']})")

Python客户端集成示例

☕ Java客户端开发指南

Java开发者可以通过HttpURLConnection或第三方HTTP客户端库与Wexflow集成。项目提供了Java客户端示例samples/clients/client/WexflowClient.java

基础Java客户端

import java.net.HttpURLConnection;
import java.net.URL;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;

public class WexflowJavaClient {
    private static final String BASE_URL = "http://localhost:8000/api/v1";
    private String token;
    
    public String login(String username, String password) throws Exception {
        URL url = new URL(BASE_URL + "/login");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/json");
        conn.setDoOutput(true);
        
        String jsonInput = String.format(
            "{\"username\":\"%s\",\"password\":\"%s\",\"stayConnected\":false}",
            username, password);
        
        try (OutputStream os = conn.getOutputStream()) {
            byte[] input = jsonInput.getBytes("utf-8");
            os.write(input);
        }
        
        if (conn.getResponseCode() != 200) {
            throw new RuntimeException("登录失败: HTTP " + conn.getResponseCode());
        }
        
        BufferedReader br = new BufferedReader(
            new InputStreamReader(conn.getInputStream(), "utf-8"));
        
        StringBuilder response = new StringBuilder();
        String responseLine;
        while ((responseLine = br.readLine()) != null) {
            response.append(responseLine.trim());
        }
        
        // 解析JSON获取token
        String json = response.toString();
        this.token = parseAccessToken(json);
        return this.token;
    }
    
    public String startWorkflow(int workflowId) throws Exception {
        if (token == null) {
            throw new IllegalStateException("请先登录");
        }
        
        URL url = new URL(BASE_URL + "/start?w=" + workflowId);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Authorization", "Bearer " + token);
        
        if (conn.getResponseCode() != 200) {
            throw new RuntimeException("启动工作流失败: HTTP " + conn.getResponseCode());
        }
        
        BufferedReader br = new BufferedReader(
            new InputStreamReader(conn.getInputStream(), "utf-8"));
        
        StringBuilder response = new StringBuilder();
        String responseLine;
        while ((responseLine = br.readLine()) != null) {
            response.append(responseLine.trim());
        }
        
        return response.toString();
    }
    
    private String parseAccessToken(String json) {
        // 简单的JSON解析,生产环境建议使用Jackson或Gson
        String tokenKey = "\"access_token\":\"";
        int start = json.indexOf(tokenKey);
        if (start == -1) return null;
        start += tokenKey.length();
        int end = json.indexOf("\"", start);
        if (end == -1) return null;
        return json.substring(start, end);
    }
}

使用OkHttp客户端

对于现代Java项目,推荐使用OkHttp:

import okhttp3.*;

public class WexflowOkHttpClient {
    private final OkHttpClient client = new OkHttpClient();
    private final String baseUrl = "http://localhost:8000/api/v1";
    private String token;
    
    public String login(String username, String password) throws Exception {
        String json = String.format(
            "{\"username\":\"%s\",\"password\":\"%s\",\"stayConnected\":false}",
            username, password);
        
        RequestBody body = RequestBody.create(
            json, MediaType.parse("application/json"));
        
        Request request = new Request.Builder()
            .url(baseUrl + "/login")
            .post(body)
            .build();
        
        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("登录失败: " + response);
            }
            
            String responseBody = response.body().string();
            // 使用JSON库解析token
            this.token = extractToken(responseBody);
            return this.token;
        }
    }
}

Java客户端开发

🌐 其他语言客户端实现

Wexflow的REST API设计简洁,可以轻松集成到任何支持HTTP请求的编程语言中。

Go语言客户端

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
)

type WexflowClient struct {
    BaseURL string
    Token   string
}

func (c *WexflowClient) Login(username, password string) error {
    url := c.BaseURL + "/login"
    
    data := map[string]interface{}{
        "username":      username,
        "password":      password,
        "stayConnected": false,
    }
    
    jsonData, _ := json.Marshal(data)
    resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData))
    if err != nil {
        return err
    }
    defer resp.Body.Close()
    
    body, _ := ioutil.ReadAll(resp.Body)
    
    var result map[string]interface{}
    json.Unmarshal(body, &result)
    
    c.Token = result["access_token"].(string)
    return nil
}

func (c *WexflowClient) StartWorkflow(workflowID int) (string, error) {
    url := fmt.Sprintf("%s/start?w=%d", c.BaseURL, workflowID)
    
    req, _ := http.NewRequest("POST", url, nil)
    req.Header.Set("Authorization", "Bearer "+c.Token)
    
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return "", err
    }
    defer resp.Body.Close()
    
    body, _ := ioutil.ReadAll(resp.Body)
    return string(body), nil
}

Node.js客户端

const axios = require('axios');

class WexflowNodeClient {
    constructor(baseUrl = 'http://localhost:8000/api/v1') {
        this.baseUrl = baseUrl;
        this.token = null;
        this.client = axios.create({
            baseURL: baseUrl,
            timeout: 10000
        });
    }
    
    async login(username, password) {
        try {
            const response = await this.client.post('/login', {
                username,
                password,
                stayConnected: false
            });
            
            this.token = response.data.access_token;
            this.client.defaults.headers.common['Authorization'] = `Bearer ${this.token}`;
            return this.token;
        } catch (error) {
            throw new Error(`登录失败: ${error.message}`);
        }
    }
    
    async startWorkflow(workflowId) {
        if (!this.token) {
            throw new Error('请先登录');
        }
        
        try {
            const response = await this.client.post(`/start?w=${workflowId}`);
            return response.data;
        } catch (error) {
            throw new Error(`启动工作流失败: ${error.message}`);
        }
    }
    
    async searchWorkflows(keyword) {
        if (!this.token) {
            throw new Error('请先登录');
        }
        
        try {
            const response = await this.client.get(`/search?s=${encodeURIComponent(keyword)}`);
            return response.data;
        } catch (error) {
            throw new Error(`搜索工作流失败: ${error.message}`);
        }
    }
}

PHP客户端

<?php

class WexflowPhpClient {
    private $baseUrl;
    private $token;
    
    public function __construct($baseUrl = 'http://localhost:8000/api/v1') {
        $this->baseUrl = $baseUrl;
    }
    
    public function login($username, $password) {
        $url = $this->baseUrl . '/login';
        
        $data = [
            'username' => $username,
            'password' => $password,
            'stayConnected' => false
        ];
        
        $options = [
            'http' => [
                'header'  => "Content-Type: application/json\r\n",
                'method'  => 'POST',
                'content' => json_encode($data),
            ],
        ];
        
        $context = stream_context_create($options);
        $result = file_get_contents($url, false, $context);
        
        if ($result === FALSE) {
            throw new Exception('登录失败');
        }
        
        $response = json_decode($result, true);
        $this->token = $response['access_token'];
        
        return $this->token;
    }
    
    public function startWorkflow($workflowId) {
        if (!$this->token) {
            throw new Exception('请先登录');
        }
        
        $url = $this->baseUrl . '/start?w=' . $workflowId;
        
        $options = [
            'http' => [
                'header'  => "Authorization: Bearer {$this->token}\r\n",
                'method'  => 'POST',
            ],
        ];
        
        $context = stream_context_create($options);
        $result = file_get_contents($url, false, $context);
        
        if ($result === FALSE) {
            throw new Exception('启动工作流失败');
        }
        
        return $result;
    }
}
?>

多语言客户端集成

🔧 高级功能与最佳实践

1. 错误处理与重试机制

在实际生产环境中,建议为客户端添加错误处理和重试机制:

import requests
from requests.exceptions import RequestException
import time

class RobustWexflowClient:
    def __init__(self, base_url, max_retries=3):
        self.base_url = base_url
        self.max_retries = max_retries
        self.token = None
    
    def start_workflow_with_retry(self, workflow_id, retry_delay=1):
        """带重试机制的工作流启动"""
        for attempt in range(self.max_retries):
            try:
                return self._start_workflow(workflow_id)
            except RequestException as e:
                if attempt == self.max_retries - 1:
                    raise
                print(f"尝试 {attempt + 1} 失败,{retry_delay}秒后重试...")
                time.sleep(retry_delay)
                retry_delay *= 2  # 指数退避
    
    def _start_workflow(self, workflow_id):
        """实际的工作流启动逻辑"""
        url = f"{self.base_url}/start?w={workflow_id}"
        headers = {"Authorization": f"Bearer {self.token}"}
        
        response = requests.post(url, headers=headers, timeout=30)
        response.raise_for_status()
        return response.json()

2. 连接池管理

对于高并发场景,合理管理HTTP连接池:

// Java中使用连接池
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;

public class WexflowHttpClient {
    private CloseableHttpClient httpClient;
    
    public WexflowHttpClient() {
        PoolingHttpClientConnectionManager cm = 
            new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(100); // 最大连接数
        cm.setDefaultMaxPerRoute(20); // 每个路由最大连接数
        
        this.httpClient = HttpClients.custom()
            .setConnectionManager(cm)
            .build();
    }
    
    // 使用连接池进行API调用
}

3. 异步处理

对于长时间运行的工作流,建议使用异步调用:

// C#异步客户端
public async Task<Guid> StartWorkflowAsync(int id, string token)
{
    var uri = $"{Uri}/start?w={id}";
    using HttpClient webClient = new();
    webClient.DefaultRequestHeaders.Authorization = 
        new AuthenticationHeaderValue("Bearer", token);
    
    var response = await webClient.PostAsync(uri, null);
    var instanceId = await response.Content.ReadAsStringAsync();
    return Guid.Parse(instanceId.Replace("\"", string.Empty));
}

// 批量异步启动工作流
public async Task<List<Guid>> StartMultipleWorkflowsAsync(
    List<int> workflowIds, string token)
{
    var tasks = workflowIds.Select(id => StartWorkflowAsync(id, token));
    return await Task.WhenAll(tasks);
}

工作流自动化处理

📊 客户端功能对比表

语言 官方支持 复杂度 性能 适用场景
C# ✅ 完整支持 优秀 .NET生态系统、Windows应用
Python ✅ 示例代码 良好 数据科学、脚本自动化
Java ✅ 示例代码 中等 优秀 企业级应用、Android
Go ⚠️ 需要自行封装 中等 优秀 微服务、高并发系统
Node.js ⚠️ 需要自行封装 良好 Web应用、实时系统
PHP ⚠️ 需要自行封装 中等 Web应用、CMS系统

🛠️ 实际应用场景

场景1:Web应用集成

// 前端通过JavaScript调用Wexflow API
async function triggerImageProcessing(imageUrl) {
    const response = await fetch('/api/wexflow/process-image', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({ imageUrl })
    });
    
    const result = await response.json();
    
    // 轮询检查工作流状态
    const jobId = result.jobId;
    let status = 'running';
    
    while (status === 'running') {
        await new Promise(resolve => setTimeout(resolve, 2000));
        const statusResponse = await fetch(`/api/wexflow/status/${jobId}`);
        status = (await statusResponse.json()).status;
    }
    
    return status === 'completed' ? '处理完成' : '处理失败';
}

场景2:后台任务调度

# 使用Celery调度Wexflow工作流
from celery import Celery
from wexflow_client import WexflowClient

app = Celery('tasks', broker='redis://localhost:6379/0')

@app.task
def process_daily_report():
    """每天定时生成报告"""
    client = WexflowClient()
    client.login('admin', 'wexflow2018')
    
    # 启动数据收集工作流
    client.start_workflow(101)
    
    # 启动报告生成工作流
    client.start_workflow(102)
    
    # 启动邮件发送工作流
    client.start_workflow(103)
    
    return "每日报告任务已调度"

# 设置定时任务
app.conf.beat_schedule = {
    'daily-report': {
        'task': 'tasks.process_daily_report',
        'schedule': 86400.0,  # 每天执行
    },
}

场景3:微服务架构集成

// Spring Boot微服务中集成Wexflow
@RestController
@RequestMapping("/api/workflows")
public class WorkflowController {
    
    @Autowired
    private WexflowService wexflowService;
    
    @PostMapping("/start/{workflowId}")
    public ResponseEntity<?> startWorkflow(
            @PathVariable int workflowId,
            @RequestBody Map<String, Object> variables) {
        
        String jobId = wexflowService.startWorkflowWithVariables(
            workflowId, variables);
        
        return ResponseEntity.ok(Map.of(
            "jobId", jobId,
            "status", "started",
            "message", "工作流已启动"
        ));
    }
    
    @GetMapping("/status/{jobId}")
    public ResponseEntity<?> getWorkflowStatus(@PathVariable String jobId) {
        WorkflowStatus status = wexflowService.getWorkflowStatus(jobId);
        return ResponseEntity.ok(status);
    }
}

微服务集成架构

🔍 调试与故障排除

常见问题与解决方案

  1. 认证失败

    • 检查用户名和密码是否正确
    • 确认Wexflow服务是否正常运行
    • 验证网络连接和端口访问
  2. 工作流启动失败

    • 检查工作流ID是否存在
    • 确认工作流是否启用
    • 查看Wexflow日志获取详细错误信息
  3. 连接超时

    • 增加HTTP请求超时时间
    • 检查防火墙设置
    • 验证Wexflow服务配置

日志记录建议

import logging
import requests

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

class LoggingWexflowClient:
    def __init__(self, base_url):
        self.base_url = base_url
        self.session = requests.Session()
        
    def start_workflow(self, workflow_id, token):
        url = f"{self.base_url}/start?w={workflow_id}"
        headers = {"Authorization": f"Bearer {token}"}
        
        logger.info(f"启动工作流 {workflow_id}")
        
        try:
            response = self.session.post(url, headers=headers, timeout=30)
            response.raise_for_status()
            
            job_id = response.json()
            logger.info(f"工作流 {workflow_id} 启动成功,作业ID: {job_id}")
            return job_id
            
        except requests.exceptions.Timeout:
            logger.error(f"启动工作流 {workflow_id} 超时")
            raise
        except requests.exceptions.RequestException as e:
            logger.error(f"启动工作流 {workflow_id} 失败: {str(e)}")
            raise

🎯 总结与建议

Wexflow的多语言客户端开发非常简单直接,主要基于REST API进行集成。无论您使用哪种编程语言,都可以通过以下几个步骤快速集成:

  1. 认证获取令牌:首先调用登录接口获取访问令牌
  2. 调用API接口:使用令牌调用各种工作流管理接口
  3. 处理响应结果:解析API返回的JSON数据
  4. 错误处理:添加适当的异常处理和重试机制

最佳实践建议

  • 使用连接池:对于频繁调用的场景,使用HTTP连接池提高性能
  • 添加超时设置:为API调用设置合理的超时时间
  • 实现重试机制:对于网络不稳定的环境,添加指数退避重试
  • 日志记录:详细记录API调用过程和结果,便于调试
  • 安全存储令牌:妥善保管访问令牌,避免泄露

性能优化技巧

  • 批量操作:尽量减少API调用次数,使用批量接口
  • 异步处理:对于长时间运行的工作流,使用异步调用
  • 缓存结果:对于不频繁变化的数据,适当使用缓存
  • 连接复用:保持HTTP连接复用,减少连接建立开销

通过本指南,您应该已经掌握了如何在各种编程语言中集成Wexflow工作流引擎。无论您是开发Web应用、桌面软件还是移动应用,都可以轻松地将Wexflow的强大自动化功能集成到您的项目中。

Wexflow多语言集成架构

立即开始您的Wexflow多语言客户端开发之旅吧! 🚀

【免费下载链接】wexflow Workflow Automation Engine 【免费下载链接】wexflow 项目地址: https://gitcode.com/gh_mirrors/we/wexflow

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐