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

如何将TinyMCE图片上传至KeystoneJS的Apollo GraphQL服务器

如何将TinyMCE图片上传对接KeystoneJS的GraphQL Mutation

我刚好做过类似的集成,核心就是把TinyMCE的images_upload_handler和Apollo Client的mutation调用结合起来,不用再写传统的XHR请求。下面是具体的实现步骤和代码示例:

核心思路

TinyMCE的images_upload_handler会提供图片的Blob信息,我们可以直接把这个Blob包装成File对象,然后调用Keystone自动生成的createImage mutation完成上传,最后把返回的图片URL交给TinyMCE插入到编辑器中。

步骤1:定义GraphQL Mutation

首先,我们需要定义Keystone生成的图片上传mutation,和你提到的结构一致:

const CREATE_IMAGE_MUTATION = gql`
  mutation CreateImage($file: Upload!) {
    createImage(data: { file: $file }) {
      id
      url # 这里根据你的Keystone Image字段配置调整,可能是publicUrl或其他字段
    }
  }
`;

步骤2:在TinyMCE上传处理器中调用Apollo Mutation

在你的Keystone自定义字段组件里,使用Apollo Client的useMutation hook获取mutation函数,然后在TinyMCE的上传处理器里调用它:

import { useMutation } from '@apollo/client';
import { gql } from '@keystone-6/core/admin-ui/apollo';
import tinymce from 'tinymce';

// 引入TinyMCE的样式和插件(根据你的项目配置调整)
import 'tinymce/skins/ui/oxide/skin.css';
import 'tinymce/plugins/image/plugin';

const TinyMCECustomField = ({ field, value, onChange }) => {
  // 获取Apollo mutation函数
  const [createImage] = useMutation(CREATE_IMAGE_MUTATION);

  const handleImageUpload = async (blobInfo, success, failure) => {
    try {
      // 从TinyMCE获取Blob和文件名
      const blob = blobInfo.blob();
      // 将Blob包装成File对象(确保文件名被正确传递)
      const file = new File([blob], blobInfo.filename(), { type: blob.type });

      // 调用Keystone的GraphQL mutation上传图片
      const { data } = await createImage({
        variables: { file }
      });

      // 将Keystone返回的图片URL传给TinyMCE,完成插入
      success(data.createImage.url);
    } catch (error) {
      // 上传失败时调用TinyMCE的failure回调提示用户
      failure(`图片上传失败: ${error.message}`);
    }
  };

  return (
    <textarea
      ref={el => {
        if (el && !el._tinymce) {
          tinymce.init({
            target: el,
            plugins: 'image',
            toolbar: 'undo redo | bold italic | image',
            // 配置自定义上传处理器
            images_upload_handler: handleImageUpload,
            // 禁用TinyMCE默认的Base64图片处理
            images_upload_base64: false,
            setup: editor => {
              // 同步编辑器内容到Keystone字段
              editor.on('input', () => onChange(editor.getContent()));
              // 初始化编辑器内容
              editor.setContent(value || '');
            }
          });
          // 标记已初始化,避免重复创建
          el._tinymce = true;
        }
      }}
    />
  );
};

export default TinyMCECustomField;

关键细节说明

  1. Blob转File的原因:
    TinyMCE提供的blobInfo.blob()是一个Blob对象,而Apollo Client的Upload类型更期望接收File对象(因为File包含文件名、文件类型等元数据)。用new File()包装一下可以确保这些信息被正确传递给Keystone的mutation。

  2. Apollo Client配置:
    Keystone 6的AdminUI默认已经集成了apollo-upload-client,所以不需要额外配置文件上传支持。如果是你自己搭建的Apollo Client,记得用createUploadLink替代普通的createHttpLink。

  3. 权限控制:
    这种方式会自动继承Keystone的权限规则,只有拥有createImage权限的用户才能上传图片,比单独写上传端点更安全。

  4. 错误处理:
    通过try-catch捕获mutation的错误,然后调用TinyMCE的failure回调,让编辑器显示错误提示,提升用户体验。

关于你的疑问

你担心的“TinyMCE提供Blob,Apollo需要文件名”的问题,确实只需要用blobInfo.filename()来获取文件名,然后把Blob包装成File对象即可——这也是最稳妥的方式,确保文件名和文件类型都能正确传递。

这种集成方式的优势在于完全复用Keystone的GraphQL生态,不需要额外维护上传接口,而且能和Keystone的权限、存储配置无缝对接。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 20:57:40