The document editing service informs the document storage service about the status of the document editing using the callbackUrl from JavaScript API. The document editing service use the POST request with the information in body.
Parameter | Description | Type | Presence |
actions |
Defines the object received when the user takes an action with the document. The type field value can have the following values:
|
array of object | optional |
changeshistory | Defines the array of objects with the document changes history. The object is present when the status value is equal to 2 or 3 only. Must be sent as a property changes of the object sent as the argument to the refreshHistory method. Removed since version 4.2, please use history instead. | array of object | optional |
changesurl | Defines the link to the file with the document editing data used to track and display the document changes history. The link is present when the status value is equal to 2, 3, 6, or 7. The file must be saved and its address must be sent as changesUrl parameter using the setHistoryData method to show the changes corresponding to the specific document version. | string | optional |
filetype | Defines an extension of the document that is downloaded from the link specified with the url parameter. The file type is OOXML by default but if the assemblyFormatAsOrigin server setting is enabled, the file will be saved in its original format. | string | optional |
forcesavetype |
Defines the type of initiator when the force saving request is performed.
Can have the following values:
|
integer | optional |
formsdataurl |
Defines the URL to the JSON file with the submitted form data.
The array structure with the form data is described here.
This file contains the following parameters:
|
object | optional |
history | Defines the object with the document changes history. The object is present when the status value is equal to 2 or 3 only. It contains the object changes and serverVersion, which must be sent as properties changes and serverVersion of the object sent as the argument to the refreshHistory method. | object | optional |
key | Defines the edited document identifier. | string | required |
status |
Defines the status of the document.
Can have the following values:
|
integer | required |
url | Defines the link to the edited document to be saved with the document storage service. The link is present when the status value is equal to 2, 3, 6 or 7 only. | string | optional |
userdata | Defines the custom information sent to the command service for the forcesave and info commands in case it was present in the request. | string | optional |
users | Defines the list of the identifiers of the users who opened the document for editing; when the document has been changed the users will return the identifier of the user who was the last to edit the document (for status 2 and status 6 replies). | array of string | optional |
The server stores all callbackUrls and chooses which one to use depending on the user who performed the action.
Since version 5.5, callbackUrl is selected depending on the status of the request. Starting from version 4.4 to version 5.5, callbackUrl is used from the last user who joined the co-editing. Prior to version 4.4, when co-editing, callbackUrl is used from the user who first opened the file for editing.
Since version 7.0, callbackUrl is used from the last tab of the same user. Prior to version 7.0, callbackUrl from the first user tab was used.
Status | Description |
Status 1 |
It is received every user connection to or disconnection from document co-editing. Their callbackUrl is used. Please note that the status 1 can be also received when the user is returned to the document with no changes after the Internet problems. This situation can be described as follows:
|
Status 2 (3) |
It is received 10 seconds after the document is closed for editing with the identifier of the user who was the last to send the changes to the document editing service. The callbackUrl from the user who made the last changes to the file is used. |
Status 4 |
It is received after the document is closed for editing with no changes by the last user. Their callbackUrl is used. |
Status 6 (7) |
It is received when the force saving request is performed. The callbackUrl depends on forcesavetype parameter:
Starting from version 5.5 to version 6.1, the callbackUrl from the user who made the last changes to the file is always used. |
{ "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" }
The document storage service must return the following response, otherwise the document editor will display an error message:
{ "error": 0 }
The document manager and document storage service are either included to ONLYOFFICE Workspace or must be implemented by the software integrators who use ONLYOFFICE Docs on their own server.
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