본문으로 건너뛰기

WOPI 어댑터 연결하기

WOPI 어댑터는 WOPI 프로토콜을 구현한 문서 서버에 Thinkfree Office(이하 웹오피스)를 연결합니다. WOPI(Web Application Open Platform Interface)는 문서를 보관하는 서버(WOPI 호스트)와 문서를 열고 편집하는 웹 앱(WOPI 클라이언트) 사이의 통신을 정한 표준 프로토콜입니다. 이미 WOPI 호스트로 동작하는 문서 관리 시스템이 있다면 저장소를 바꾸지 않고 웹오피스를 편집기로 연결할 수 있습니다.

다른 어댑터와 다른 점

다른 어댑터와 달리 문서를 여는 주체는 WOPI 호스트입니다. 개발자가 웹오피스의 문서 URL을 직접 만드는 대신, 호스트가 웹오피스의 discovery 정보를 읽고 문서별 접근 토큰을 담아 편집기를 엽니다. 그래서 이 가이드는 관리자 페이지에 어댑터를 등록하는 방법과 함께, WOPI 호스트에서 웹오피스를 여는 방법까지 설명합니다.

연결 정보 준비하기

WOPI 호스트의 파일 엔드포인트 주소와 웹오피스 주소를 준비합니다.

항목준비할 값
파일 엔드포인트WOPI 호스트가 파일 요청을 받는 주소. 웹오피스가 {FILE_ENDPOINT}/{FILE_ID} 형식으로 호출합니다.
예: https://wopi.example.com/wopi/files. 웹오피스 서버에서 접근할 수 있어야 합니다.
웹오피스 주소사용자의 브라우저가 편집기에 접근하는 웹오피스 주소. 경로 없이 스킴, 호스트와 포트만 사용합니다.
예: http://localhost:8080

WOPI 호스트는 다음 WOPI 작업을 구현해야 합니다. 웹오피스는 접근 토큰을 access_token 쿼리 파라미터와 Authorization: Bearer 헤더로 함께 보내므로, 호스트는 둘 중 한 가지로 토큰을 검증합니다.

WOPI 작업요청용도
CheckFileInfoGET {FILE_ENDPOINT}/{FILE_ID}문서 이름, 크기, 권한과 사용자 이름 조회. 문서 열기에 필수
GetFileGET {FILE_ENDPOINT}/{FILE_ID}/contents문서 내용 다운로드. 문서 열기에 필수
Lock, RefreshLock, UnlockPOST {FILE_ENDPOINT}/{FILE_ID}X-WOPI-Override 헤더편집 중 잠금 획득, 연장과 해제
PutFilePOST {FILE_ENDPOINT}/{FILE_ID}/contentsX-WOPI-Override: PUT 헤더편집한 문서 전체 저장

웹오피스는 CheckFileInfo 응답에서 다음 항목을 사용합니다.

CheckFileInfo 항목웹오피스의 사용
BaseFileName편집기에 표시할 문서 이름. 확장자로 문서 형식을 판단합니다.
Size문서 크기
UserCanWritetrue일 때만 저장할 수 있습니다.
UserFriendlyName협업자 목록과 커서에 표시할 사용자 이름. 없으면 UserId를 사용합니다.

WOPI 어댑터 추가하기

아래 캡처는 관리자 페이지의 입력 예입니다. WOPI Host URL에는 사용하는 호스트의 파일 엔드포인트를 입력합니다.

관리자 페이지의 WOPI 어댑터 추가 양식

  1. 웹오피스 관리자 페이지외부연동에서 어댑터 추가를 누릅니다.
  2. 어댑터 유형에서 WOPI를 선택합니다.
  3. 다음 연결 정보를 입력합니다.
항목입력할 값
이름wopi. 편집기 실행 페이지가 이 이름으로 어댑터를 찾으므로 다른 이름을 사용하지 않습니다.
설명어댑터의 용도. 미리 입력된 설명을 그대로 두어도 됩니다.
WOPI Host URL파일 엔드포인트. 경로까지 입력합니다.
예: https://wopi.example.com/wopi/files
WOPI Client Domain웹오피스 주소. 경로 없이 입력합니다.
예: http://localhost:8080
  1. 등록을 누릅니다. WOPI는 문서별 접근 토큰이 있어야 호스트를 호출할 수 있으므로 연결 테스트 없이 등록합니다.
  2. 어댑터 목록에서 wopi가 실행 중인지 확인합니다.

WOPI Host URL은 웹오피스가 문서를 열 때 요청을 보내는 유일한 주소입니다. 호스트가 보낸 WOPISrc에서 파일 ID를 제외한 앞부분이 이 값과 다르면 웹오피스는 문서 열기를 거부합니다. WOPI Client Domain은 discovery XML의 편집기 실행 주소 앞부분으로 사용됩니다.

WOPI 어댑터는 하나만 등록합니다

discovery XML은 실행 중인 WOPI 어댑터 1개의 WOPI Client Domain을 사용합니다. 호스트를 바꾸려면 등록한 어댑터를 수정합니다.

discovery 확인하기

어댑터를 등록한 뒤 웹오피스 주소에 /hosting/discovery를 붙여 요청하면 WOPI 호스트가 읽을 discovery XML을 확인할 수 있습니다.

curl http://localhost:8080/hosting/discovery

응답에는 파일 확장자별 편집기 실행 주소와 요청 검증용 공개 키가 들어 있습니다. 아래는 응답의 일부입니다.

<wopi-discovery>
<net-zone name="external-http">
<app name="writer">
<action default="true" ext="docx" name="edit" requires="update,locks" urlsrc="http://localhost:8080/hosting/word.html?"/>
<action default="true" ext="dotx" name="view" urlsrc="http://localhost:8080/hosting/word_v.html?"/>
</app>
<app name="calc">
<action default="true" ext="xlsx" name="edit" requires="update,locks" urlsrc="http://localhost:8080/hosting/spreadsheet.html?"/>
</app>
<app name="presentation">
<action default="true" ext="pptx" name="edit" requires="update,locks" urlsrc="http://localhost:8080/hosting/presentation.html?"/>
</app>
</net-zone>
<proof-key value="..." modulus="..." exponent="AQAB" oldvalue="..." oldmodulus="..." oldexponent="AQAB"/>
</wopi-discovery>

urlsrc의 앞부분은 관리자 페이지에 입력한 WOPI Client Domain입니다. WOPI 어댑터가 없거나 중지된 상태에서는 503 응답과 함께 어댑터를 등록하라는 메시지가 표시됩니다.

WOPI 호스트에서 문서 열기

편집기 실행 주소 선택하기

호스트는 discovery XML의 action 중에서 문서의 확장자(ext)와 동작(name)이 맞는 항목의 urlsrc를 선택합니다. edit은 편집기, view는 뷰어를 엽니다.

문서편집기 urlsrc뷰어 urlsrc
Word (docx 등){WOPI_CLIENT_DOMAIN}/hosting/word.html?{WOPI_CLIENT_DOMAIN}/hosting/word_v.html?
Cell (xlsx 등){WOPI_CLIENT_DOMAIN}/hosting/spreadsheet.html?{WOPI_CLIENT_DOMAIN}/hosting/spreadsheet_v.html?
Show (pptx 등){WOPI_CLIENT_DOMAIN}/hosting/presentation.html?{WOPI_CLIENT_DOMAIN}/hosting/presentation_v.html?

편집기 실행 요청 보내기

호스트는 선택한 urlsrc 뒤에 WOPISrc 쿼리 파라미터를 붙이고, 접근 토큰을 access_token 폼 필드에 담아 브라우저에서 POST로 전송합니다. WOPISrc에는 파일 엔드포인트 뒤에 파일 ID를 한 구간으로 붙인 주소를 URL 인코딩해 넣습니다.

아래는 파일 ID가 doc-001인 Word 문서를 편집기로 여는 폼 예제입니다.

<form method="post" action="http://localhost:8080/hosting/word.html?WOPISrc=https%3A%2F%2Fwopi.example.com%2Fwopi%2Ffiles%2Fdoc-001">
<input type="hidden" name="access_token" value="{ACCESS_TOKEN}" />
<button type="submit">Open in Office</button>
</form>

웹오피스는 이 요청을 받아 파일 ID와 접근 토큰으로 편집기를 엽니다. access_token이 없으면 400 응답을 반환합니다. WOPISrc에서 파일 ID를 제외한 앞부분은 관리자 페이지의 WOPI Host URL과 같아야 합니다. 위 예제에서는 https://wopi.example.com/wopi/files입니다.

접근 토큰은 호스트가 사용자와 문서별로 발급하고 검증하는 값입니다. 웹오피스는 토큰의 내용을 해석하지 않고 호스트에 보내는 모든 요청에 그대로 담습니다.

웹오피스가 호스트에 보내는 요청 확인하기

편집기가 열리면 웹오피스는 다음 순서로 호스트를 호출합니다. 모든 요청의 URL에는 access_token 쿼리 파라미터가 붙습니다.

시점요청헤더
문서를 열 때GET {FILE_ENDPOINT}/{FILE_ID} (CheckFileInfo)-
문서를 열 때GET {FILE_ENDPOINT}/{FILE_ID}/contents (GetFile)-
편집을 시작할 때POST {FILE_ENDPOINT}/{FILE_ID} (Lock)X-WOPI-Override: LOCK, X-WOPI-Lock: TFO:{FILE_ID}
편집 중 10분마다POST {FILE_ENDPOINT}/{FILE_ID} (RefreshLock)X-WOPI-Override: REFRESH_LOCK, X-WOPI-Lock: TFO:{FILE_ID}
저장할 때POST {FILE_ENDPOINT}/{FILE_ID}/contents (PutFile)X-WOPI-Override: PUT, X-WOPI-Lock: TFO:{FILE_ID}
편집을 마치고 문서를 닫을 때POST {FILE_ENDPOINT}/{FILE_ID} (Unlock)X-WOPI-Override: UNLOCK, X-WOPI-Lock: TFO:{FILE_ID}

잠금 ID는 문서 단위로 TFO:{FILE_ID}입니다. 같은 문서를 여는 모든 사용자가 같은 잠금 ID를 보내므로, 호스트는 이미 같은 ID로 잠긴 문서의 Lock 요청을 잠금 갱신으로 처리해야 공동 편집이 동작합니다. 다른 잠금 ID로 잠긴 문서에는 409 응답과 함께 현재 잠금 ID를 X-WOPI-Lock 헤더로 알려 줍니다. WOPI 표준에 따라 호스트는 30분 동안 갱신되지 않은 잠금을 만료시킬 수 있으며, 웹오피스는 만료 전에 잠금을 연장합니다.

PutFile은 편집한 문서 전체를 요청 본문으로 보냅니다. 호스트는 X-WOPI-Lock이 현재 잠금과 같을 때만 저장하고, 성공하면 200을 반환합니다.

요청 검증하기

웹오피스는 호스트에 보내는 모든 요청에 X-WOPI-Proof, X-WOPI-ProofOld, X-WOPI-TimeStamp 헤더를 붙입니다. 호스트는 discovery XML의 proof-key에 있는 공개 키로 서명을 검증해 요청이 웹오피스에서 왔는지 확인할 수 있습니다.

  • X-WOPI-Proof는 현재 키(value)로, X-WOPI-ProofOld는 이전 키(oldvalue)로 서명한 값입니다. 웹오피스는 키를 6개월 주기로 교체하므로 두 헤더 중 하나가 검증되면 요청을 신뢰합니다.
  • X-WOPI-TimeStamp는 요청 시점을 .NET ticks 단위로 표시합니다. 웹오피스는 요청마다 새 값을 만들므로 호스트는 20분보다 오래된 타임스탬프를 거부할 수 있습니다.
  • 검증에 실패한 요청에는 오류 응답의 X-WOPI-ServerError 헤더에 사유를 적습니다. 웹오피스가 이 값을 로그에 남기므로 원인을 찾기 쉬워집니다.

연결 확인하기

  1. 호스트에서 Word 문서를 열어 웹오피스 편집기가 새 창 또는 프레임에 표시되는지 확인합니다.
  2. 문서를 편집하고 저장한 뒤, 호스트가 PutFile 요청을 받아 문서를 갱신했는지 확인합니다.
  3. 문서를 닫고 다시 열어 변경 내용이 유지되는지 확인합니다.
  4. 두 사용자가 같은 문서를 열어 공동 편집이 동작하는지 확인합니다.

문제가 생기면 다음을 확인합니다.

증상확인할 것
discovery 요청이 503을 반환합니다.WOPI 어댑터가 등록되어 있고 실행 중인지 확인합니다.
편집기 대신 오류 페이지가 표시됩니다.어댑터 이름이 wopi인지, WOPISrc에서 파일 ID를 제외한 앞부분이 WOPI Host URL과 같은지 확인합니다.
편집기 실행 요청이 400을 반환합니다.폼에 access_token 필드가 있는지 확인합니다.
호스트가 401을 반환합니다.호스트의 접근 토큰 검증 로직과 토큰 유효 기간을 확인합니다.
Lock 요청이 409를 반환합니다.다른 클라이언트가 문서를 잠갔는지 확인합니다. 잠금 ID가 TFO:{FILE_ID}이면 잠금 갱신으로 처리합니다.
문서는 열리지만 저장되지 않습니다.CheckFileInfo의 UserCanWritetrue인지, PutFile이 X-WOPI-Lock을 검증한 뒤 200을 반환하는지 확인합니다.

더 알아보기: WOPI 연동의 동작 흐름

WOPI 연동은 문서를 보관하는 WOPI 호스트, 문서를 편집하는 WOPI 클라이언트인 웹오피스, 그리고 두 서버 사이를 오가는 사용자 브라우저로 구성됩니다. 관리자 페이지에 WOPI 어댑터를 등록하면 웹오피스가 /hosting/discovery에서 WOPI discovery XML을 제공하기 시작하고, 그 뒤의 연동은 그림의 번호 순서로 동작합니다.

사용자 브라우저WOPI Host문서 저장소접근 토큰 발급 · 요청 검증WOPI ClientThinkfree Office편집기 · 뷰어① discovery XML 읽기GET /hosting/discovery② 편집기 실행 요청WOPISrc · access_token③ 편집기 열기urlsrc④ 문서 조회 · 잠금 · 저장CheckFileInfo · GetFile · Lock · PutFile
  1. WOPI 호스트가 discovery XML을 읽어 파일 확장자별 편집기 실행 주소(urlsrc)와 요청 검증용 공개 키(proof-key)를 확인합니다.
  2. 사용자가 호스트에서 문서를 열면, 호스트는 문서 주소(WOPISrc)와 접근 토큰(access_token)을 담아 브라우저를 편집기 실행 주소로 보냅니다.
  3. 브라우저가 편집기 실행 주소로 이동하면 웹오피스가 편집기를 엽니다.
  4. 웹오피스는 접근 토큰으로 호스트에 문서 정보와 내용을 요청해 문서를 표시하고, 편집 중에는 잠금을 유지하며, 저장할 때 변경한 문서를 호스트에 전달합니다.

다음 단계