文档编辑服务 用 JavaScript API的 callbackUrl 通知 文档存储服务 有关文档编辑的状态。 文档编辑服务 使用POST 请求,请求信息在正文中。
参数 | 描述 | 类型 | 出现 |
actions |
定义当用户对文档执行操作时接收到的对象。type 字段值可以具有以下值:
|
object数组 | 可选的 |
changeshistory | 定义具有文档更改历史的对象数组。仅当 status 值等于 2 或 3 时,对象才存在。 必须作为对象的属性 changes 以参数形式发送给 refreshHistory 方法。 自 4.2 版起已删除,请改用 history。 | object数组 | 可选的 |
changesurl | 使用文档编辑数据定义文件的链接,用于跟踪和显示文档更改历史记录。 仅当 status 等于 2 或 3 时,链接才存在。必须保存文件,并且必须使用 setHistoryData 方法将其地址作为 changesUrl 参数发送,以显示与特定文档版本对应的更改。 | string | 可选的 |
filetype | 定义从 url 参数指定的链接下载文档的扩展名。 文件类型默认为 OOXML,但如果启用了 assemblyFormatAsOrigin 服务器设置,则文件将以原始格式保存。 | string | 可选的 |
forcesavetype | 定义执行 强制保存 请求时的启动器类型。 可以有以下值: 该类型仅在 status 值等于 6 或 7 时出现。 | integer | 可选的 |
formsdataurl |
用提交的表单数据,定义 JSON 文件的 URL。
此处描述了包含表单数据的数组结构。
该文件包含以下参数:
|
对象 | 可选的 |
history | 定义有文档更改历史的对象。 仅当 status 值等于 2 或 3 时,对象才存在。它包含对象 changes 和 serverVersion,它们必须作为对象的属性 changes 和 serverVersion 以参数形式发送给 refreshHistory 方法。 | 对象 | 可选的 |
key | 定义编辑的文档标识符。 | string | 必需的 |
status |
定义文档的状态。
可以有以下值:
|
integer | 必需的 |
url | 定义已编辑的要由文档存储服务保存的文档的链接。 仅当 status 值等于 2, 3, 6 或 7 时,链接才存在。 | string | 可选的 |
userdata | 定义发送到forcesave 和 info 命令的命令服务的自定义信息(如果它在请求中存在)。 | string | 可选的 |
users | 定义打开文档进行编辑的用户的标识符列表;当文档被更改时,用户将返回最后编辑文档的用户的标识符(对于 status 2 和 status 6 的应答)。 | string数组 | 可选的 |
从 5.5 版本开始,根据请求的 status 选择 callbackUrl。 从 4.4 到 5.5 版本, callbackUrl 来自最后一个加入共同编辑的用户。 在 4.4 之前的版本中,在共同编辑时, callbackUrl 来自第一次打开文件进行编辑的用户。
从 7.0 版开始, callbackUrl 来自同一用户的最后一个标签。在 7.0 版之前, callbackUrl 来自第一个用户标签。
状态 | 描述 |
status 1 |
每次用户连接或断开文档共同编辑时都会收到它。他们的 callbackUrl 被使用。 请注意,当用户在遭遇Internet 故障后返回到没有更改的文档时也可以收到 status 1。这种情况可以描述如下:
|
Status 2 (3) |
它在编辑文档关闭后 10 秒 收到,该用户的标识符是最后一个将更改发送到文档编辑服务的用户。 对文件进行最后更改的用户的 callbackUrl 被使用。 |
Status 4 |
它是在最后一个用户关闭所编辑的没有更改的文档情况下收到的。他们的 callbackUrl 被使用。 |
Status 6 (7) |
在执行强制保存请求时接收到。 callbackUrl 依赖于 forcesavetype 参数:
从版本 5.5 到版本 6.1,始终使用对文件进行最后更改的用户的 callbackUrl。 |
{ "actions": [{"type": 1, "userid": "78e1e841"}], "key": "Khirz6zTPdfd7", "status": 1, "users": ["6d5a81d0", "78e1e841"] }
{ "actions": [{"type": 0, "userid": "78e1e841"}], "changesurl": "https://documentserver/url-to-changes.zip", "history": { "changes": changes, "serverVersion": serverVersion }, "filetype": "docx", "key": "Khirz6zTPdfd7", "status": 2, "url": "https://documentserver/url-to-edited-document.docx", "users": ["6d5a81d0"] }
{ "key": "Khirz6zTPdfd7", "status": 4 }
{ "changesurl": "https://documentserver/url-to-changes.zip", "forcesavetype": 0, "history": { "changes": changes, "serverVersion": serverVersion }, "filetype": "docx", "key": "Khirz6zTPdfd7", "status": 6, "url": "https://documentserver/url-to-edited-document.docx", "users": ["6d5a81d0"], "userdata": "sample userdata" }
文档存储服务 必须返回以下响应,否则 文档编辑器 将显示错误消息:
{ "error": 0 }
文档管理器 和 文档存储服务 要么包含在社区版服务器中,要么必须由在自己的服务器上使用 ONLYOFFICE 文档服务器的软件集成商实施。
public class WebEditor : IHttpHandler { public void ProcessRequest(HttpContext context) { string body; using (var reader = new StreamReader(context.Request.InputStream)) body = reader.ReadToEnd(); var fileData = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(body); if ((int) fileData["status"] == 2) { var req = WebRequest.Create((string) fileData["url"]); using (var stream = req.GetResponse().GetResponseStream()) using (var fs = File.Open(PATH_FOR_SAVE, FileMode.Create)) { var buffer = new byte[4096]; int readed; while ((readed = stream.Read(buffer, 0, 4096)) != 0) fs.Write(buffer, 0, readed); } } context.Response.Write("{\"error\":0}"); } }
public class IndexServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter writer = response.getWriter(); Scanner scanner = new Scanner(request.getInputStream()).useDelimiter("\\A"); String body = scanner.hasNext() ? scanner.next() : ""; JSONObject jsonObj = (JSONObject) new JSONParser().parse(body); if((long) jsonObj.get("status") == 2) { String downloadUri = (String) jsonObj.get("url"); URL url = new URL(downloadUri); java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection(); InputStream stream = connection.getInputStream(); File savedFile = new File(pathForSave); try (FileOutputStream out = new FileOutputStream(savedFile)) { int read; final byte[] bytes = new byte[1024]; while ((read = stream.read(bytes)) != -1) { out.write(bytes, 0, read); } out.flush(); } connection.disconnect(); } writer.write("{\"error\":0}"); } }
var fs = require("fs"); var syncRequest = require("sync-request"); app.post("/track", function (req, res) { var updateFile = function (response, body, path) { if (body.status == 2) { var file = syncRequest("GET", body.url); fs.writeFileSync(path, file.getBody()); } response.write("{\"error\":0}"); response.end(); } var readbody = function (request, response, path) { var content = ""; request.on("data", function (data) { content += data; }); request.on("end", function () { var body = JSON.parse(content); updateFile(response, body, path); }); } if (req.body.hasOwnProperty("status")) { updateFile(res, req.body, pathForSave); } else { readbody(req, res, pathForSave) } });
<?php if (($body_stream = file_get_contents("php://input"))===FALSE){ echo "Bad Request"; } $data = json_decode($body_stream, TRUE); if ($data["status"] == 2){ $downloadUri = $data["url"]; if (($new_data = file_get_contents($downloadUri))===FALSE){ echo "Bad Response"; } else { file_put_contents($path_for_save, $new_data, LOCK_EX); } } echo "{\"error\":0}"; ?>
class ApplicationController< ActionController::Base def index body = request.body.read file_data = JSON.parse(body) status = file_data["status"].to_i if status == 2 download_uri = file_data["url"] uri = URI.parse(download_uri) http = Net::HTTP.new(uri.host, uri.port) if download_uri.start_with?("https") http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE end req = Net::HTTP::Get.new(uri.request_uri) res = http.request(req) data = res.body File.open(path_for_save, "wb") do |file| file.write(data) end end render :text =>"{\"error\":0}" end end