如何在React组件中获取Transloadit上传至GCS的最终链接并解决状态异常
问题描述
我在React组件中使用Uppy+Transloadit上传文件到Google Cloud Storage(最终链接以https://storage.googleapis.com/...开头),遇到两个问题:
- 无法清晰找到获取最终文件链接的方法,相关文档说明不够明确
- 文件明明已经成功上传,但Transloadit对象的
ok字段始终返回"ASSEMBLY_UPLOADING",而非预期的"ASSEMBLY_COMPLETED"
相关代码如下:
uppy.on('complete', (result) => { console.log(result) })
UppyDashboard.tsx
'use client' import themeModeState from '@/recoils/themeMode/themeModeState' import '@uppy/core/dist/style.css' import '@uppy/dashboard/dist/style.css' import { Dashboard } from '@uppy/react' import '@uppy/url/dist/style.css' import * as React from 'react' import { useRecoilValue } from 'recoil' import { useEffect, useState } from 'react' import createUppy from '@/components/uppy/createUppy' export interface IUppyDashboard { // ... } const UppyDashboard: React.FC<IUppyDashboard> = ({ templateId, authKey, authSecret, }) => { const themeMode = useRecoilValue(themeModeState) const houseId = 'mainHouse' const roomId = 'mainRoom' const [uppy] = useState(() => createUppy({ ids: { houseId, roomId, }, authKey, authSecret, templateId, }) ) useEffect(() => { if (houseId && roomId) { uppy.setOptions({ meta: { houseId, roomId } }) } }, [uppy, houseId, roomId]) uppy.on('complete', (result) => { console.log(result) }) return ( <Dashboard uppy={uppy} plugins={[ // 'Webcam', 'Dropbox', 'GoogleDrive', 'Facebook', 'OneDrive', 'Box', 'Url', ]} metaFields={[ { id: 'name', name: 'Name', placeholder: 'Image name' }, { id: 'caption', name: 'Caption', placeholder: 'Describe what the image is about', }, ]} showLinkToFileUploadResult={false} waitForThumbnailsBeforeUpload={true} showSelectedFiles={true} replaceTargetContent={true} showProgressDetails={false} note="Images only, 1–4 files, up to 5 MB" height="350px" width="auto" theme={themeMode || 'auto'} /> ) } export default UppyDashboard
createUppy.tsx
import Compressor from '@uppy/compressor' import Uppy from '@uppy/core' import Url from '@uppy/url' import GoogleDrive from '@uppy/google-drive' import Facebook from '@uppy/facebook' import OneDrive from '@uppy/onedrive' import Dropbox from '@uppy/dropbox' import Box from '@uppy/box' import ImageEditor from '@uppy/image-editor' // @ts-ignore import Hebrew from '@uppy/locales/lib/he_IL' import Transloadit, { COMPANION_URL } from '@uppy/transloadit' import expires from './dateString' import createSignature from './transloaditSignature' type CreateUppy = { ids: { houseId: string roomId: string } authKey: string authSecret: string templateId: string } const createUppy = (props: CreateUppy) => { const { ids, authKey, authSecret, templateId } = props const { houseId, roomId } = ids if (!authKey || !authSecret) { throw new Error('Missing auth key or secret') } const signature = createSignature({ authKey, authSecret, expires, templateId, }) // Adding to global `meta` will add it to every file. // Every Uppy instance needs a unique ID. return new Uppy({ id: roomId, meta: { houseId, roomId }, locale: Hebrew, autoProceed: false, restrictions: { allowedFileTypes: ['image/*'], maxNumberOfFiles: 4, minNumberOfFiles: 1, minFileSize: 1000, maxFileSize: 5 * 1024 * 1024, // 5 MB }, }) .use(Transloadit, { // Import files from Companion using the /import-files Robot // importFromUploadURLs: true, assemblyOptions(file: any) { return { params: { auth: { key: authKey, expires }, template_id: templateId, }, signature, // You can use these inside your template // https://transloadit.com/docs/topics/assembly-instructions/#form-fields-in-instructions fields: { roomId: file.meta.roomId, houseId: file.meta.houseId }, // waitForEncoding: true, } }, }) .use(Compressor) .use(Url, { companionUrl: COMPANION_URL }) .use(GoogleDrive, { companionUrl: COMPANION_URL }) .use(Facebook, { companionUrl: COMPANION_URL }) .use(OneDrive, { companionUrl: COMPANION_URL }) .use(Dropbox, { companionUrl: COMPANION_URL }) .use(Box, { companionUrl: COMPANION_URL }) } export default createUppy
解决方法
1. 修复ASSEMBLY_UPLOADING状态问题
当前代码中Transloadit插件的waitForEncoding选项被注释,导致Uppy仅在文件上传完成后就触发complete事件,而非等待Transloadit完成所有编码/导出流程。
修改createUppy.tsx中的Transloadit配置:
.use(Transloadit, { assemblyOptions(file: any) { return { params: { auth: { key: authKey, expires }, template_id: templateId, }, signature, fields: { roomId: file.meta.roomId, houseId: file.meta.houseId }, waitForEncoding: true, // 取消注释并设置为true } }, })
开启该选项后,Uppy会等待Transloadit完成整个Assembly流程(包括上传到GCS),此时ok字段会正确返回"ASSEMBLY_COMPLETED"。
2. 获取Google Cloud Storage最终文件链接
开启waitForEncoding后,complete事件的result对象中,每个文件的transloadit.assembly.results会包含Transloadit的处理结果,其中就有GCS的存储链接。
修改UppyDashboard.tsx中的complete事件监听:
useEffect(() => { const handleComplete = (result) => { result.successful.forEach(file => { const assemblyResults = file.transloadit?.assembly?.results; if (assemblyResults) { // 替换为你Transloadit模板中导出到GCS的Robot名称 const gcsExportResults = assemblyResults.your_export_robot_name; if (gcsExportResults && gcsExportResults.length > 0) { const gcsUrl = gcsExportResults[0].url; console.log('GCS文件链接:', gcsUrl); // 可将链接存入状态或发送至后端 } } }); }; uppy.on('complete', handleComplete); return () => uppy.off('complete', handleComplete); // 组件卸载时移除监听 }, [uppy]);
注意:your_export_robot_name需要替换为你Transloadit模板中,用于将文件导出到GCS的Robot名称(即模板中该步骤的name属性值)。
额外注意事项
- 确保Transloadit模板已正确配置Google Cloud Storage导出步骤,且Assembly能正常完成导出
- 检查
expires变量的时间范围,避免在Assembly完成前签名过期 - 在React组件中,务必将事件监听放在
useEffect中,避免重复绑定
内容的提问来源于stack exchange,提问作者Yedidya
相关产品推荐
相关产品推荐

