Cloudflare-5 分钟开发专属 Flux 文生图 API,实现生图自由!

1- Cloudflare 5 分钟开发专属 Flux 文生图 API,实现生图自由

1.1- 引言

" 活菩萨 "Cloudflare 为我们提供了很多免费的资源和服务。本文将详细介绍如何基于 Cloudflare Workers AI 开发一个专属的 Flux Schnell 文生图 API。有了该 API 之后,基于它开发一个MCP Server就可以实现生图 " 自由 "。

其实,除了实现文生图功能外,我们还可以基于 Workers AI 实现多种 AI 功能:

  • 文本 Embedding
  • 对象检测
  • 文本分类
  • 图片分类
  • 语音识别等

Cloudflare Workers AI功能概览

1.2- Cloudflare 免费额度说明

Cloudflare 每天都提供免费的额度,如果不是高频使用,日常开发和测试基本够用:

1.2.1- 免费额度

免费额度

1.2.2- flux-1-schnell 模型消耗

flux-1-schnell消耗

1.3- 项目概述

在本教程中,我们将:

  1. 从零搭建 Cloudflare Workers 项目
  2. 配置并接入 Flux 文生图模型
  3. 实现安全、稳定的 API 接口
  4. 部署并测试我们的服务

完成后,你将拥有一个可用于个人项目或集成到其他应用的专属文生图 API。

了解完 Cloudflare Workers AI 之后,下面我们来从零开发一个专属的 Flux API。

2- 从零开发专属 Flux API

前置条件

  1. 本地已安装 Node.js
  2. 已拥有 Cloudflare 账号

2.1- 项目初始化

pnpm create cloudflare@latest cf-flux-schnell

成功运行以上命令之后,就按照引导进行项目初始化。这里主要展示前面三个步骤,其它步骤根据需求自行选择。

2.1.1- 1.选择 Starter

图片

2.1.2- 2.选择模板

图片

2.1.3- 3.选择编程语言

图片

2.2- 配置 Workers AI

在完成项目初始化之后,要使用 Workers AI,我们还需要在项目根目录下的 wrangler.jsonc 文件中配置 AI binding。

{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "cf-flux-schnell",
"main": "src/index.ts",
"compatibility_date": "2025-03-12",
"observability": {
"enabled": true
},
"ai": {
"binding": "AI"
}
}

具体如下图所示:图片

2.3- 了解 flux-1-schnell API

在开发专属的flux schnell API之前,我们需要先阅读 Cloudflare 的官方文档,该文档为开发者提供了开箱即用的示例。

exportinterface Env {
  AI: Ai;
}

exportdefault {
async fetch(request, env): Promise<Response> {
const response = await env.AI.run('@cf/black-forest-labs/flux-1-schnell', {
    prompt: 'a cyberpunk lizard',
  });
// response.image is base64 encoded which can be used directly as an <img src=""> data URI
const dataURI = `data:image/jpeg;charset=utf-8;base64,${response.image}`;
return Response.json({ dataURI });
  },
} satisfies ExportedHandler<Env>;

由以上代码可知,使用 Workers AI,我们只需关注模型名称、模型输入和模型输出

从官方文档中,我们可以获得模型输入和模型输出的 schemas。

2.3.1- Input

{
"type": "object",
"properties": {
"prompt": {
"type": "string",
"minLength": 1,
"maxLength": 2048,
"description": "A text description of the image you want to generate."
    },
"steps": {
"type": "integer",
"default": 4,
"maximum": 8,
"description": "The number of diffusion steps; higher values can improve quality but take longer."
    }
},
"required": [
"prompt"
]
}

2.3.2- Output

{
"type": "object",
"contentType": "application/json",
"properties": {
"image": {
"type": "string",
"description": "The generated image in Base64 format."
    }
}
}

2.4- 开发 flux-1-schnell API

官方提供的示例,比较简单,prompt 参数也是写死的。因此,我们需要对该示例进行重构。

2.4.1- 项目目录结构

在开始编码前,我们先来规划一下项目的目录结构:

cf-flux-schnell/
├── node_modules/
├── src/
│   ├── index.ts         # 主入口文件
│   ├── errors.ts        # 错误处理类
│   ├── schemas.ts       # 数据验证模式
│   └── utils.ts         # 工具函数
├── wrangler.jsonc       # Cloudflare Workers 配置
├── package.json
└── README.md

2.4.2- 定义类型和接口

在开始实现功能前,我们需要定义一些类型和接口来提高代码的可维护性:

// src/types.ts
export interface Env {
  AI: any; // Cloudflare AI binding
}

export interface GenerateImageRequest {
  prompt: string;
  steps?: number;
}

export interface GenerateImageResponse {
  image: string; // Base64编码的图片数据
}

2.4.2.1- 1. 增加请求参数校验

我们使用主流的校验库 —— zod,来校验请求参数,在使用 zod 之前,需要先安装它:

pnpm add zod

成功安装 zod 之后,我们定义 GenerateImageSchema,用于校验请求参数。

// src/schemas.ts
import { z } from 'zod';

export const GenerateImageSchema = z.object({
  prompt: z.string().min(1, 'Prompt cannot be empty').max(2048, 'Prompt must not exceed 2048 characters'),
  steps: z.number().int().min(1).max(8).default(4).optional(),
});

export type GenerateImageSchemaType = z.infer<typeof GenerateImageSchema>;

2.4.2.2- 2. 自定义异常对象

为了更好地处理各种异常情况,我们定义了 ValidationErrorUnauthorizedErrorMethodNotAllowedError 异常对象。

// src/errors.ts
import { z } from "zod";

export class ApiError extends Error {
  constructor(public status: number, message: string, public details?: unknown) {
    super(message);
    this.name = 'ApiError';
  }
}

export class ValidationError extends ApiError {
  constructor(details: z.ZodError) {
    super(400, 'Validation error', details.errors);
    this.name = 'ValidationError';
  }
}

export class UnauthorizedError extends ApiError {
  constructor() {
    super(401, 'Unauthorized');
    this.name = 'UnauthorizedError';
  }
}

export class MethodNotAllowedError extends ApiError {
  constructor() {
    super(405, 'Method not allowed');
    this.name = 'MethodNotAllowedError';
  }
}

2.4.2.3- 3. 请求方法调整为 Post 并增加 Authorization 校验

为了提高接口的安全性,我们为接口增加了 Authorization 校验。

// src/utils.ts
import { GenerateImageSchema } from './schemas';
import { ApiError, MethodNotAllowedError, UnauthorizedError, ValidationError } from './errors';
import { z } from 'zod';

// 设置 API Token,实际项目中应该使用环境变量
export const FLUX_TOKEN = 'Y2YtZmx1eC1hcGk='; // 这是一个示例令牌,实际使用时请更换

export const validateRequest = async (request: Request): Promise<z.infer<typeof GenerateImageSchema>> => {
  // 只允许 POST 请求
  if (request.method !== 'POST') {
    throw new MethodNotAllowedError();
  }

  // 验证授权令牌
  const authHeader = request.headers.get('Authorization');
  const expectedToken = FLUX_TOKEN;

  if (!authHeader || authHeader !== `Bearer ${expectedToken}`) {
    throw new UnauthorizedError();
  }

  try {
    // 解析并验证请求体
    const body = await request.json();
    return GenerateImageSchema.parse(body);
  } catch (error) {
    if (error instanceof z.ZodError) {
      throw new ValidationError(error);
    }
    throw new ApiError(400, 'Invalid request body');
  }
};

2.4.2.4- 4. 处理异常和响应

为了方便处理异常和创建响应对象,我们封装了 createJsonResponsehandleError 方法。

// src/utils.ts (继续)

/**
 * 创建JSON响应
 */
export const createJsonResponse = (data: unknown, status = 200): Response => {
  return new Response(JSON.stringify(data), {
    status,
    headers: { 'Content-Type': 'application/json' },
  });
};

/**
 * 处理错误并生成适当的响应
 */
export const handleError = (error: unknown): Response => {
  console.error('Error processing request:', error);

  if (error instanceof ApiError) {
    return createJsonResponse(
      {
        error: error.message,
        details: error.details ? error.details : undefined,
      },
      error.status
    );
  }

  return createJsonResponse(
    {
      error: 'Internal server error',
      details: error instanceof Error ? error.message : 'Unknown error',
    },
    500
  );
};

2.4.2.5- 5. 更新 fetch 方法

完成前面的步骤之后,最后需要更新 fetch 方法的函数体:

// src/index.ts
import { Env, GenerateImageResponse } from './types';
import { validateRequest, createJsonResponse, handleError } from './utils';

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    try {
      // 验证请求
      const validatedData = await validateRequest(request);

      // 调用 Flux 模型生成图片
      const response = await env.AI.run('@cf/black-forest-labs/flux-1-schnell', {
        prompt: validatedData.prompt,
        steps: validatedData.steps,
      });

      // 处理响应
      const result: GenerateImageResponse = {
        image: response.image ? `data:image/png;base64,${response.image}` : '',
      };

      return createJsonResponse(result);
    } catch (error) {
      return handleError(error);
    }
  },
} satisfies ExportedHandler<Env>;

2.4.3- 错误处理和日志记录

在生产环境中,适当的错误处理和日志记录对于问题排查至关重要。Cloudflare Workers 提供了内置的日志工具,我们可以使用它来记录重要信息:

// 在 handleError 函数中添加日志记录
export const handleError = (error: unknown): Response => {
  // 详细记录错误信息
  console.error('Error processing request:', error);
  
  if (error instanceof ApiError) {
    // 记录结构化的错误信息
    console.error({
      type: error.name,
      status: error.status,
      message: error.message,
      details: error.details
    });
    
    return createJsonResponse(
      {
        error: error.message,
        details: error.details ? error.details : undefined,
      },
      error.status
    );
  }
  
  return createJsonResponse(
    {
      error: 'Internal server error',
      details: error instanceof Error ? error.message : 'Unknown error',
    },
    500
  );
};

2.5- 测试与部署

2.5.1- 1. 本地测试服务

在正式部署之前,我们可以在本地环境进行测试。Wrangler 提供了简便的本地开发服务器,你可以通过以下命令启动它:

pnpm dev

执行此命令后,Wrangler 会在本地启动一个开发服务器,默认监听在 http://127.0.0.1:8787。你可以使用 Postman、Insomnia 或 curl 来测试 API。

本地测试示例:

curl --request POST \
  --url http://127.0.0.1:8787/ \
  --header 'Authorization: Bearer Y2YtZmx1eC1hcGk=' \
  --header 'Content-Type: application/json' \
  --data '{
  "prompt": "A beautiful landscape with mountains and a lake, watercolor style",
  "steps": 4
}'

2.5.2- 2. 部署远程服务

确认本地测试无误后,我们可以将服务部署到 Cloudflare Workers 平台:

pnpm run deploy

部署过程中,Wrangler 会提示你登录 Cloudflare 账号(如果尚未登录),并处理部署流程。成功部署后,你会看到类似以下信息:

✨ Successfully published your script to
https://cf-flux-schnell.yourusername.workers.dev

2.5.3- 3. 接口测试

当部署成功之后,你可以通过 Postman 或 curl 来测试已部署的flux-1-schnell API接口。

curl --request POST \
  --url https://cf-flux-schnell.yourusername.workers.dev/ \
  --header 'Authorization: Bearer Y2YtZmx1eC1hcGk=' \
  --header 'Content-Type: application/json' \
  --data '{
  "prompt": "1girl, cute, drinking water, glass cup, morning light, cartoon style, simple background",
  "steps": 4
}'

成功的响应示例:

{
  "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
}

你可以将返回的 base64 图片数据直接用于 HTML 的 img 标签:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." alt="Generated Image" />

3- API 应用与集成

3.1- 安全性考虑

在将 API 用于生产环境之前,建议加强以下安全措施:

  1. 使用环境变量存储 Token:不要在代码中硬编码 API 令牌,应使用 Cloudflare 的环境变量:
// wrangler.toml
[vars]
FLUX_API_TOKEN = "your-secure-token"

// 在代码中使用
const token = env.FLUX_API_TOKEN;
  1. 请求限流:防止 API 被滥用,可以添加请求频率限制:
// 使用Cloudflare的限流服务
export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    // 为每个IP添加限流
    const ip = request.headers.get('CF-Connecting-IP');
    const rateLimitKey = `rate_limit:${ip}`;
    
    // 检查是否超过限制
    // ... 限流逻辑 ...
    
    // 继续处理请求
    // ...
  }
}
  1. CORS 设置:如果 API 需要从浏览器跨域访问,需要设置正确的 CORS 头:
function addCorsHeaders(response: Response): Response {
  const newHeaders = new Headers(response.headers);
  newHeaders.set('Access-Control-Allow-Origin', 'https://your-allowed-domain.com');
  newHeaders.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
  newHeaders.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  
  return new Response(response.body, {
    status: response.status,
    statusText: response.statusText,
    headers: newHeaders
  });
}

// 在返回响应之前添加CORS头
return addCorsHeaders(createJsonResponse(result));

3.2- 集成到前端应用

将我们的 Flux API 集成到前端应用非常简单。这里是一个 React 组件示例:

// ImageGenerator.jsx
import React, { useState } from 'react';
import './ImageGenerator.css';

const API_URL = 'https://cf-flux-schnell.yourusername.workers.dev/';
const API_TOKEN = 'Y2YtZmx1eC1hcGk='; // 在实际应用中,应通过安全方式管理

function ImageGenerator() {
  const [prompt, setPrompt] = useState('');
  const [steps, setSteps] = useState(4);
  const [generatedImage, setGeneratedImage] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');

  const generateImage = async () => {
    setLoading(true);
    setError('');
    
    try {
      const response = await fetch(API_URL, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${API_TOKEN}`
        },
        body: JSON.stringify({ prompt, steps })
      });
      
      if (!response.ok) {
        const errorData = await response.json();
        throw new Error(errorData.error || '图片生成失败');
      }
      
      const data = await response.json();
      setGeneratedImage(data.image);
    } catch (err) {
      setError(err.message || '请求过程中发生错误');
      console.error('生成图片出错:', err);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="image-generator">
      <h2>AI图像生成器</h2>
      
      <div className="input-group">
        <label htmlFor="prompt">描述你想要的图像:</label>
        <textarea
          id="prompt"
          value={prompt}
          onChange={(e) => setPrompt(e.target.value)}
          placeholder="例如: 一只可爱的猫咪在阳光下玩耍"
        />
      </div>
      
      <div className="input-group">
        <label htmlFor="steps">生成步数 (1-8):</label>
        <input
          type="number"
          id="steps"
          min="1"
          max="8"
          value={steps}
          onChange={(e) => setSteps(Number(e.target.value))}
        />
      </div>
      
      <button 
        onClick={generateImage} 
        disabled={loading || !prompt.trim()}
      >
        {loading ? '生成中...' : '生成图像'}
      </button>
      
      {error && <div className="error">{error}</div>}
      
      {generatedImage && (
        <div className="result">
          <h3>生成的图像:</h3>
          <img src={generatedImage} alt="AI生成的图像" />
        </div>
      )}
    </div>
  );
}

export default ImageGenerator;

对应的 CSS 样式:

/* ImageGenerator.css */
.image-generator {
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
  font-family: 'Microsoft YaHei', sans-serif;
}

.input-group {
  margin-bottom: 15px;
}

label {
  display: block;
  margin-bottom: 5px;
  font-weight: bold;
}

textarea {
  width: 100%;
  height: 100px;
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-family: 'Microsoft YaHei', sans-serif;
}

input[type="number"] {
  width: 60px;
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
}

button {
  background-color: #1677ff;
  color: white;
  border: none;
  padding: 10px 20px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
  font-family: 'Microsoft YaHei', sans-serif;
}

button:disabled {
  background-color: #cccccc;
  cursor: not-allowed;
}

.error {
  color: #ff4d4f;
  margin: 10px 0;
}

.result {
  margin-top: 20px;
}

.result img {
  max-width: 100%;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

3.3- 常见问题解决

在使用 Flux API 过程中,可能会遇到一些常见问题,这里提供一些解决方案:

3.3.1- 请求超时

Cloudflare Workers 有 30 秒的执行时间限制。如果生成较高质量的图像需要更多时间,可能会导致请求超时。解决方案:

  1. 降低 steps 参数值(默认为 4,最高为 8)
  2. 简化提示词(prompt)
  3. 考虑使用异步处理模式,通过 Cloudflare 的 Durable Objects 或 Workers KV 存储结果

3.3.2- 请求失败

如果遇到请求失败的情况,可以检查以下几点:

  1. 确认 Authorization 头部是否正确设置
  2. 检查请求格式是否符合要求
  3. 查看 Cloudflare Workers 的日志,确认具体错误

3.3.3- 提高生成图像质量

要提高生成图像的质量,可以:

  1. 增加 steps 参数的值(最高为 8)
  2. 优化提示词,使用更具体、更详细的描述
  3. 使用正确的艺术风格关键词,如 “watercolor”、“oil painting”、“photorealistic” 等

3.4- API 扩展思路

有了基础的 Flux API,我们可以进一步扩展其功能:

image

4- Flux 文生图模型使用技巧

4.1- Flux 模型特点与优势

Flux 是 Cloudflare 提供的一款高效文生图模型,其特点包括:

  1. 快速生成:相比其他大型模型,Flux 能够在几秒钟内生成图像,非常适合实时应用
  2. 低资源消耗:Flux 模型针对边缘计算优化,可以在资源有限的环境下高效运行
  3. 良好的创意表现:尽管是轻量级模型,但在创意图像生成方面表现良好
  4. 免费额度友好:Cloudflare 提供的免费额度对于个人开发者和小型项目足够使用

4.2- 提示词(Prompt)工程技巧

要从 Flux 模型获得最佳效果,优质的提示词至关重要:

4.2.1- 基本结构

一个好的提示词通常包含以下元素:

  • 主体内容:想要生成的主要对象/人物
  • 场景描述:背景、环境、光线条件
  • 风格指导:艺术风格、渲染方式
  • 质量描述:期望的画质、细节程度

4.2.2- 示例与效果

以下是几个提示词示例及其可能产生的效果:

  1. 简单描述:

    "a cat"
    

    效果: 生成一只基本的猫,但缺乏细节和特色

  2. 增强描述:

    "a fluffy orange cat sitting by the window, morning sunlight, detailed fur, cozy home atmosphere"
    

    效果: 生成一只更加生动的橙色猫咪,有光影效果和环境氛围

  3. 风格定向:

    "a cyberpunk cityscape with neon lights, flying cars, digital billboards, cinematic lighting, inspired by Blade Runner"
    

    效果: 生成具有特定风格和参考的科幻城市场景

4.2.3- 常用风格关键词

以下是一些可以显著影响生成效果的风格关键词:

  • 艺术风格:watercolor, oil painting, digital art, pixel art, vaporwave, cyberpunk
  • 摄影风格:portrait, landscape, macro photography, aerial view, fisheye lens
  • 光线条件:golden hour, blue hour, backlight, dramatic lighting, soft lighting
  • 质量描述:highly detailed, intricate details, 4K, photorealistic, masterpiece

4.2.4- 常见问题与解决方法

  1. 模糊或低质量输出

    • 解决方法:添加 “highly detailed”、“sharp focus” 等质量描述词
  2. 风格不一致

    • 解决方法:明确指定一种艺术风格,如 “in the style of [艺术家/风格]”
  3. 比例或构图问题

    • 解决方法:指定视角和构图,如 “front view”、“wide angle” 等
  4. 过度拥挤或简单

    • 解决方法:调整描述的复杂度,对于简单画面使用 “minimalist” 等词汇

4.3- 与其他模型的比较

为了帮助大家更好地理解 Flux 模型的定位,这里简单对比几种常见的文生图模型:

特性 Flux (Cloudflare) Midjourney DALL-E 3 Stable Diffusion
速度 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐
图像质量 ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
创意多样性 ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
易用性 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐
成本 ⭐⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐
自托管能力 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐

Flux 的主要优势在于速度快、成本低和易于集成,非常适合需要快速响应的应用场景或作为其他模型的备选方案。

5- 总结

有了 flux-1-schnell API 之后,你可以根据需要调整一下相关的代码,就可以接入其它的 AI 模型。在开发的过程中,如果有遇到问题,可以跟我联系。如果你对如何把flux-1-schnell API封装成 MCP Server 感兴趣,可以给我留言哟。

完整代码:

https://gist.github.com/bytefer/6ea44e54c37c276b9c2cca4244ec32e2