Bỏ qua, tới nội dung
Tài liệu APIv1

Nhúng trình soạn thảo

Xử lý lỗi và giới hạn kết nối

Bảng mã lỗi của lớp nhúng, quy tắc chống SSRF, hành vi khi chạm trần kết nối ở trình duyệt, và các giới hạn thời gian, kích thước.

Trong trang này

Mọi lỗi tới trang của bạn qua onError với {code, message, detail}: code ổn định để rẽ nhánh, message là câu tiếng Việt hiện được cho người dùng. Chạm trần kết nối không phải lỗi và đi qua onLimitReached.

Lỗi từ máy chủ#

HTTPcodeKhi nàoNên làm gì
400invalid_configThiếu hoặc sai trường; detail.errors = [{path, message}].Sửa config; đừng thử lại.
401token_requiredMáy chủ yêu cầu JWT nhưng config không có.Ký config ở máy chủ.
401invalid_tokenChữ ký sai, không phải HS256, thiếu exp, exp xa quá 24 giờ.Kiểm khoá và thuật toán.
401token_expiredQuá exp.Xin token mới rồi mở lại.
401embed_auth_not_configuredMáy chủ chưa đặt khoá và không bật chế độ không ký.Quản trị đặt O3O_EMBED_JWT_SECRET.
401invalid_session_tokenAuthorization không khớp phiên.Tạo phiên mới.
403origin_not_allowedOrigin không nằm trong O3O_EMBED_ALLOWED_ORIGINS.Thêm origin của trang.
403invalid_signatureChữ ký URL tải tệp sai.Dùng nguyên URL gate trả về.
404not_foundPhiên hoặc tài liệu không tồn tại; hoặc lớp nhúng bị tắt.Kiểm O3O_EMBED_ENABLED.
410link_expired, version_goneURL tải hết hạn; phiên bản đã bị dọn.Tải sớm hơn, trong thời gian giữ.
413file_too_largeVượt O3O_EMBED_MAX_FILE_MB (mặc định 100 MB).Không thử lại.
415unsupported_file_typefileType ngoài danh sách hoặc máy chủ soạn thảo không mở được.Không thử lại.
422url_not_allowedVi phạm quy tắc chống SSRF.Dùng URL công cộng hoặc khai O3O_FETCH_ALLOW_HOSTS.
422download_failedKhông tải được document.url.Kiểm máy chủ tệp; có thể thử lại.
503editor_unavailableGate không lấy được discovery của máy chủ soạn thảo.Thử lại sau; báo quản trị.

Lỗi chỉ có ở trình duyệt#

codeKhi nào
network_errorKhông gọi được máy chủ O3O.
load_failedKhung soạn thảo báo nạp hỏng, hoặc tài liệu không hiện sau 120 giây.
save_failedKhung soạn thảo báo lưu không thành công; detail chứa nguyên thông điệp.
save_timeoutsave() quá 30 giây.

Quy tắc chống SSRF#

Áp cho mọi URL mà máy chủ tự gọi (document.url, callbackUrl): chỉ http/https, không có user:pass@, tối đa 2048 ký tự; mọi địa chỉ phân giải ra phải là địa chỉ công cộng (địa chỉ riêng, loopback, link-local, multicast đều bị chặn), và gate nối thẳng tới đúng địa chỉ IP đã kiểm, không phân giải lại (chống DNS rebinding); không tự theo chuyển hướng (tải thì tự xử lý tối đa 3 lần và xét lại từng chặng, callback thì coi chuyển hướng là thất bại); chỉ mã 200 là tải thành công. Ngoại lệ có chủ đích duy nhất: O3O_FETCH_ALLOW_HOSTS.

Khi chạm trần kết nối#

  • Trang xin mode: "edit" khi current + pending >= limit: gate vẫn tạo phiên nhưng ở view, trả limited: true, và api.js phát onLimitReached.
  • api.js chèn phía trên khung một băng nền vàng nhạt có nút tắt, với đúng câu message của máy chủ. Tắt băng này bằng ui.limitBanner: false.
  • Phiên đang sửa không bao giờ bị ngắt, lưu không bao giờ bị chặn.
  • Mở lại đúng tài liệu vừa rời trong 120 giây được cho vào kể cả khi đã đầy (mất mạng chớp nhoáng, tải lại trang).
  • Trần của bản cộng đồng là 50; bản doanh nghiệp theo số kết nối đã mua. Xem hạn mứccác gói.
201Trả lời tạo phiên khi đã chạm trần
{
  "session_id": "ses_0c4e9a1b2d3f4a5b6c7d8e9f",
  "key": "contract-42-v7",
  "doc_id": "doc_9835f61009fc659dfedab8696f2d2665",
  "mode": "view",
  "requested_mode": "edit",
  "limited": true,
  "limit": {
    "limit": 50,
    "current": 50,
    "edition": "community"
  },
  "message": "Hệ thống đã đạt giới hạn 50 phiên soạn thảo đồng thời của bản cộng đồng. Tài liệu của bạn vẫn an toàn. Bạn có thể mở ở chế độ chỉ đọc hoặc thử lại sau ít phút.",
  "editor_url": "/browser/825c9caa93/cool.html?WOPISrc=http%3A%2F%2Fo3o-gate%3A8070%2Fo3o%2Fwopi%2Ffiles%2Fdoc_9835f61009fc659dfedab8696f2d2665&lang=vi&permission=readonly",
  "form": {
    "access_token": "kq3…",
    "access_token_ttl": 1790043200000,
    "ui_defaults": "UIMode=notebookbar"
  },
  "version": 0,
  "expires_at": "2026-09-21T22:00:00Z"
}
HTMLXử lý lỗi và chạm trần theo cách của bạn
<div id="banner" hidden style="background: #fff4d6; padding: 8px 12px"></div>
<div id="o3o-editor" style="height: 90vh"></div>
<script src="http://localhost:8080/o3o/api.js"></script>
<script>
  let editor;
  let retries = 0;

  async function openEditor() {
    // Máy chủ của bạn trả config đã ký (xem trang Ký cấu hình bằng JWT)
    const config = await (await fetch("/o3o/config?doc=42")).json();
    editor = new O3O.Editor("o3o-editor", {
      ...config,
      ui: { ...(config.ui || {}), limitBanner: false },    // tự vẽ băng thông báo
      events: { onDocumentLoaded: () => { retries = 0; }, onError, onLimitReached }
    });
  }

  function onError(e) {
    switch (e.code) {
      case "token_expired":        // token quá hạn: xin config mới và mở lại
      case "network_error":        // không gọi được O3O: thử lại, giãn cách tăng dần
      case "load_failed":
        if (retries++ < 3) {
          editor.destroy();
          setTimeout(openEditor, 2000 * retries);
          return;
        }
        break;
      case "save_failed":
      case "save_timeout":         // tài liệu vẫn mở, nhắc người dùng lưu lại
        return showBanner("Chưa lưu được. Vui lòng bấm lưu lần nữa.");
      case "url_not_allowed":
      case "download_failed":
      case "file_too_large":
      case "unsupported_file_type": // lỗi do tệp hoặc URL: thử lại không giúp gì
        return showBanner(e.message);
    }
    showBanner(e.message);
    console.error(e.code, e.detail);
  }

  function onLimitReached(e) {
    // Không phải lỗi: tài liệu đã mở ở chế độ chỉ đọc
    showBanner(e.message, "Thử sửa lại", () => editor.setReadOnly(false));
  }

  function showBanner(text, actionLabel, action) {
    const el = document.getElementById("banner");
    el.textContent = text;
    if (actionLabel) {
      const b = document.createElement("button");
      b.textContent = actionLabel;
      b.onclick = action;
      el.append(" ", b);
    }
    el.hidden = false;
  }

  openEditor();
</script>

Các giới hạn khác#

Giới hạnGiá trị mặc địnhBiến
Kích thước tệp nhúng (tải về và lưu lên)100 MBO3O_EMBED_MAX_FILE_MB
Thời hạn access_token của phiên720 phútO3O_EMBED_SESSION_TTL_MINUTES
Phiên tạo xong mà trình soạn thảo không nạphuỷ sau 300 giâyO3O_EMBED_PENDING_TTL_SECONDS
Giữ bản làm việc sau khi đóng24 giờO3O_EMBED_RETAIN_HOURS
Chờ tài liệu hiện120 giây, rồi load_failedcố định
save()30 giây, rồi save_timeoutcố định
close() chờ lưu10 giâycố định

Trang nhúng ở origin khác#

Trang trên localhost (cổng bất kỳ) nhúng được mà không cần cấu hình. Trang ở origin khác cần hai việc: thêm origin vào O3O_EMBED_ALLOWED_ORIGINS (CORS của /o3o/embed/*), và đặt O3O_ONLINE_FRAME_ANCESTORS (một giá trị không có dấu cách, ví dụ https://app.example.com hoặc https://*.example.com) để trình duyệt cho phép nhúng khung. Nhiều origin rời nhau trong O3O_ONLINE_FRAME_ANCESTORS: sắp có.