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

实现WOPI协议时如何用服务端axios替代POST表单加载Collabora Online

问题根因

你之前的方案无法运行主要有3个核心问题:

  • 直接将Collabora返回的HTML通过srcDoc注入iframe,会导致HTML内的相对路径静态资源、后续接口请求全部指向你的前端域名,找不到对应资源
  • Collabora运行依赖正确的域名上下文,直接在你的前端域名下运行Collabora的代码会触发跨域限制,后续WOPI协议相关的接口全部无法调用
  • 服务端axios请求参数格式错误,没有按照原表单的要求传递access_token表单字段,请求直接被Collabora拒绝
正确实现方案

我们采用Express做代理转发的方式实现,既满足服务端发起请求的要求,又保留iframe加载的正确上下文逻辑:

1. 服务端实现

首先安装依赖:

npm install form-data axios

路由代码如下:

const FormData = require('form-data');
const axios = require('axios');

// 辅助方法:流转字符串
const streamToString = (stream) => {
  const chunks = [];
  return new Promise((resolve, reject) => {
    stream.on('data', chunk => chunks.push(chunk));
    stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
    stream.on('error', reject);
  });
};

routeAuthenticated(
  'POST',
  '/MyRequest',
  async (req, res) => {
    try {
      const { url, token } = req.body;
      // 构造和原表单完全一致的form-data参数
      const form = new FormData();
      form.append('access_token', token);

      // 发起请求到Collabora
      const collaboraRes = await axios.post(url, form, {
        headers: form.getHeaders(),
        responseType: 'stream'
      });

      // 透传所有响应头
      Object.keys(collaboraRes.headers).forEach(key => {
        res.setHeader(key, collaboraRes.headers[key]);
      });
      res.status(collaboraRes.status);

      // 处理HTML响应,插入base标签修正资源路径
      if (collaboraRes.headers['content-type']?.includes('text/html')) {
        const html = await streamToString(collaboraRes.data);
        const collaboraOrigin = new URL(url).origin;
        // 插入base标签,所有相对路径资源自动指向Collabora域名
        const modifiedHtml = html.replace('<head>', `<head><base href="${collaboraOrigin}/">`);
        res.send(modifiedHtml);
        return;
      }

      // 非HTML类响应直接转发流
      collaboraRes.data.pipe(res);
    } catch (err) {
      console.error('代理请求失败:', err);
      res.status(500).send('服务端代理请求出错');
    }
  }
);

2. 客户端实现

表单组件代码

不需要修改原有iframe的逻辑,仅把表单的提交地址改为自己的Express代理接口即可:

import { useRef, useEffect } from 'react';

const CollaboraSubmitForm = (props) => {
  const formElem = useRef(null);

  useEffect(() => {
    formElem.current.submit();
  }, []);

  return (
    <div style={{display: 'none'}}>
      <form
        ref={formElem}
        action="/MyRequest"
        encType="multipart/form-data"
        method="post"
        target="collabora-online-viewer"
        id="collabora-submit-form"
      >
        <input
          name="url"
          value={props.url}
          type="hidden"
        />
        <input
          name="token"
          value={props.token}
          type="hidden"
        />
        <input type="submit" value="" />
      </form>
    </div>
  );
};

export default CollaboraSubmitForm;

iframe组件代码

和你原有实现完全一致,不需要额外加srcDoc相关逻辑:

<iframe
  ref={iframeRef}
  title="Collabora Online Viewer"
  id="collabora-online-viewer"
  name="collabora-online-viewer"
  style={{ width: '100%', height: '90vh', border: 'none' }}
/>
注意事项
  • 如果你的Collabora服务配置了自定义域名或者路径,记得调整base标签的href值适配
  • 后续WOPI接口如果也需要走代理,可以在Express新增对应的代理路由统一处理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 21:18:02