邵阳建设网站的公司,网站后台做链接,公司旅游视频网站模板,广州网络帮助建站一个客户项目有引进在线文档操作需求#xff0c;让我这边做一个demo调研下#xff0c;给我的对接文档里有相关方法的说明#xff0c;照着对接即可。但在真正对接过程中还是踩过不少坑#xff0c;这儿对之前的对接工作做个记录。 按照习惯先来一个效果#xff1a; Demo下载…一个客户项目有引进在线文档操作需求让我这边做一个demo调研下给我的对接文档里有相关方法的说明照着对接即可。但在真正对接过程中还是踩过不少坑这儿对之前的对接工作做个记录。 按照习惯先来一个效果 Demo下载链接https://download.csdn.net/download/qxyywy/88117444 接入指引 1. 申请授权证书并进行授权。 2. 登录系统后台页面 3. 创建、获取应用信息 access_key 简称ak、 secret_key 简称 sk 。开发者在接口调用时使用ak 、 sk 生成WPS-4签名进行鉴权。 4. 在线编辑、在线预览、格式转换接入按照对应开放能力文档接入。在线编辑、在线预览对接过程中需要设置回调地址。其中在线编辑可通过配置开启历史版本功能。 5. 使用过程中需通过证书查询接口关注授权证书状态若证书即将过期或者不可用需进行更新证书操作。 6. 在线编辑或在线预览服务端对接完毕对接方可使用JSSDK调用API实现相关需求。 WPS-4签名算法
在对接时耗费了一定时间在WPS-4签名处对接文档中有WPS-4的说明和样例自己在对接转换成NetCore的时候踩了一些坑签名算法中最主要是Wps-Docs-Authorization的计算方法 签名格式WPS-4 {accessKey}:{signature} 注意WPS-4后面有空格。 signature:hmac-sha256(secret_key, Ver HttpMethod URI Content-Type WpsDocs-Date sha256(HttpBody)) signature的样例如下WPS-4POST/callback/path/demoapplication/jsonWed, 20 Apr 2022 01:33:07GMTfc005f51a6e75586d2d5d078b657dxxxdf9c1dfa6a7c0c0ba38c715daeb6ede9 这是文档中对签名算法的解释对照着格式完成相关算法具体算法如下signature的组装 /// summary/// 获取签名/// /summary/// param namemethod请求方法如GET,POST/param/// param nameuri请求url带querystring/param/// param namebody请求body/param/// param namedate日期/param/// param namecontentType默认application/json/param/// param namesecretKey应用SK/param/// returns/returnspublic static string WPS4Signature(string secretKey,string method,string uri, byte[] bodynull,DateTime? datenull,string contentType application/json){//获取uri路径string path uri;//日期格式化if (date null)date DateTime.Now;string dateStr String.Format({0:r}, date);//open不参与签名做替换处理if (path.StartsWith(/open)){path path.Replace(/open, );}string sha256body;//body为空则为空否则返回sha256(body)if (body ! null body.Length 0){sha256body Sha256(body);}else{sha256body ;}String signature null;signature HmacSHA256Encrypt($WPS-4{method.ToUpper()}{path}{contentType}{dateStr}{sha256body}, secretKey);return signature;}
HmacSHA256加密算法 /// summary/// HmacSHA256加密/// /summary/// param namesecret/param/// param namesignKey/param/// returns/returnspublic static string HmacSHA256Encrypt(string secret, string signKey){string signRet string.Empty;using (HMACSHA256 mac new HMACSHA256(Encoding.UTF8.GetBytes(signKey))){byte[] hash mac.ComputeHash(Encoding.UTF8.GetBytes(secret));//signRet Convert.ToBase64String(hash);signRet ToHexStrFromByte(hash); }return signRet;}
Sha256转换 /// summary/// Sha256转换/// /summary/// param nameinputThe input./param/// returnsA hash./returnspublic static string Sha256(this byte[] input){if (input null){return null;}using (var sha SHA256.Create()){var hash sha.ComputeHash(input);return ToHexStrFromByte(hash);}}
字节数组转16进制字符串 /// summary/// 字节数组转16进制字符串空格分隔/// /summary/// param namebyteDatas/param/// returns/returnspublic static string ToHexStrFromByte(this byte[] byteDatas){StringBuilder builder new StringBuilder();for (int i 0; i byteDatas.Length; i){builder.Append(string.Format({0:X2}, byteDatas[i]));}return builder.ToString().Trim().ToLower();}
获取在线预览链接 /// summary/// 获取在线预览链接/// /summary/// param namerequest/param/// returns/returns[Route(api/wps/previewgenarate)][HttpPost]public TaskGenarateResult GenarateWPSPreviewUrl(GenarateRequest request){return Task.Run(() {string wpsHost http://10.4.**.**;string uri $/api/preview/v1/files/{defaultFileId}/link?typewpreview_modehigh_definition;string fullUrl ${wpsHost}/open{uri};Dictionarystring, string headers new Dictionarystring, string();DateTime now DateTime.Now;headers.Add(Content-Type, application/json);headers.Add(Wps-Docs-Date, String.Format({0:r}, now));var signature WPSLocalSIgnatureHelper.WPS4Signature(SKrpaxjdwoetijjv, get, uri, null, now);string docsAuthorization WPSLocalSIgnatureHelper.WPS4SignAuthorization(UOMYPEVAHWQLTKJF, signature);headers.Add(Wps-Docs-Authorization, docsAuthorization);HttpHelper httpHelper new HttpHelper();var resultTemp httpHelper.Get(fullUrl, headers);var result JsonConvert.DeserializeObjectResponseBaseModelOnlineEditResultModel(resultTemp);string url ;if (result ! null result.data ! null){url result.data.link;}return new GenarateResult { Url url };});}
这儿比较坑的地方来了,方法参数都组装好了通过HttpWebRequest后端发起请求获取WPS中台返回的在线预览地址时始终提示401报错获取不到数据。迫不得已自己通过APIPost组装了相关请求和参数居然又能获取到相关数据。对照了下请求头又差异后调整了程序的请求头保证和apiPost里的完全一致依然返回401通过查阅相关资料找到一个处理办法在发起的请求后手动捕获WebException然后在WebException里解析数据流获取信息。HttpWebRequest Get方式访问 /// summary/// Get方式访问/// /summary/// param nameurl/param/// param nameencode/param/// param namereferer/param/// param nameheaders/param/// returns/returnspublic string Get(string url, string encode, string referer, Dictionarystring, string headersnull){int num _tryTimes;HttpWebRequest request null;HttpWebResponse response null;StreamReader reader null;while (num-- 0){try{DelaySomeTime();ServicePointManager.ServerCertificateValidationCallback new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult);//验证服务器证书回调自动验证request (HttpWebRequest)WebRequest.Create(url);request.Headers.Add(accept, */*);request.Headers.Add(accept-encoding, gzip, deflate, br);request.Headers.Add(accept-language, zh-CN);request.Headers.Add(connection, keep-alive);if (headers ! null) {foreach (var item in headers){request.Headers.Add(item.Key, item.Value);}}//request.UserAgent reqUserAgent;request.CookieContainer _cookie;request.Referer referer;request.Method GET;request.Timeout _timeOut;if (_proxy ! null _proxy.Credentials ! null){request.UseDefaultCredentials true;}request.Proxy _proxy;response (HttpWebResponse)request.GetResponse();reader new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(encode));return reader.ReadToEnd();}catch (WebException ex){response (HttpWebResponse)ex.Response; //解析401等错误返回的有效信息var resultTemp ;Stream stream response.GetResponseStream();using (StreamReader readers new StreamReader(stream, Encoding.UTF8)){resultTemp readers.ReadToEnd();}return resultTemp;}catch (Exception ex){_logger.Error(url \r\n ex.ToString());continue;}finally{if (request ! null){request.Abort();}if (response ! null){response.Close();}if (reader ! null){reader.Close();}}}return string.Empty;}
DemoHtml 到上面时后端的处理就基本完成前端这边因为时临时demo就用了一个html来处理真实项目中需要用VUE等处理也都类似。 以下为 html的代码
!DOCTYPE html
htmlheadmeta charsetUTF-8 /!-- 建议禁用外框浏览器自带的缩放 --metanameviewportcontentwidthdevice-width, initial-scale1.0, maximum-scale1.0, minimum-scale1.0,user-scalableno/meta http-equivX-UA-Compatible contentieedge /titleWPS Web Office(iframe)接入指南/titlestyle* {box-sizing: border-box;}html,body {display: flex;flex-direction: column;padding: 0;margin: 0;height: 100%;/* 防止双击缩放 */touch-action: manipulation;}iframe {flex: 1;}/style!-- cdn引入JQ --script srchttps://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.4.1.min.js/scriptscript src./jwps.js/scriptscript typetext/javascriptvar appHost http://10.4.146.19:8890;// 支持 HTTPS// 注意如果通过postMessage来设置token请在url参数加上_w_tokentype1function showWPS(url) {// 初始化var wps WPS.config({mount: document.querySelector(#wpsPanl),// 文字wpsUrl: url,headers: {shareBtn: {tooltip: 分享,subscribe: function() {console.log(click callback);}},otherMenuBtn: {tooltip: 其他按钮,items: [{// 自定义, type 固定填 customtype: custom,icon:http://ep.wps.cn/index/images/logo_white2.png,text: API 导出 PDF,subscribe: function(wps) {if (wps.WpsApplication) {wps.WpsApplication().ActiveDocument.ExportAsFixedFormatAsync().then(function(result) {console.table(result);});}}},{// 自定义, type 固定填 customtype: custom,icon:http://ep.wps.cn/index/images/logo_white2.png,text: API 使用,subscribe: function(wps) {let result;if (wps.WpsApplication) {wps.WpsApplication().ActiveDocument.ExportAsFixedFormatAsync().then(function(result) {console.table(result);});}}}]}}});return wps;}window.onload function() {$.ajax({url: appHost/api/wps/previewgenarate,contentType: application/json,dataType: json,data: JSON.stringify({fileId: a123,fileName: test.docx,fileType: 1,userId: 1505340867}),type: post,success: function(res) {var wpsUrl res.url;console.log(wpsUrl);var wps showWPS(wpsUrl);}});var fileInput document.getElementById(bookimg1);//选择文件fileInput.addEventListener(change, function () {//如果未传入文件则中断if (fileInput.files[0] undefined) {return;}var file fileInput.files[0];//FileReader可直接将上传文件转化为二进制流var reader new FileReader();reader.readAsDataURL(file);//转化二进制流异步方法reader.onload function (result) {//完成后this.result为二进制流var base64Str this.result;$(#uploadImg).attr(src, base64Str);$(#imgPreview).show();} })};function replaceWps() {$(.tdname1).html($(#name1).val());$(.tddept1).html($(#dept1).val());$(.tdage1).html($(#age1).val());$(.tdname2).html($(#name2).val());$(.tddept2).html($(#dept2).val());$(.tdage2).html($(#age2).val());var fileBytes ;var fileName ;if ($(#bookimg1)[0].files[0] ! undefined) {var imgFile $(#bookimg1)[0].files[0];fileName imgFile.name;//FileReader可直接将上传文件转化为二进制流var reader new FileReader();reader.readAsDataURL(imgFile);//转化二进制流异步方法reader.onload function (result) {//完成后this.result为二进制流var base64Str this.result;var startNum base64Str.indexOf(base64,);startNum startNum * 1 7;//去除前部格式信息如果有需求var baseStr base64Str.slice(startNum);fileBytes baseStr;$.ajax({url: appHost /api/wps/wrapheader,contentType: application/json,dataType: json,data: JSON.stringify({sample_list: [{bookmark: bookmark1,type: TEXT,text: $(#bookmark1).val()},{bookmark: bookmark2,type: TEXT,text: $(#bookmark2).val()},{bookmark: bookmark3,type: TEXT,text: $(#bookmark3).val()},{bookmark: bookimg1,type: IMAGE,/*sample_url:$(#bookimg1).val(),*/sample_filename: fileName,text: fileBytes,},{bookmark: bookform1,type: TEXT,text: $(#testForm).prop(outerHTML)}],}),type: post,success: function (res) {var wpsUrl res.url;;var wps showWPS(wpsUrl);}});}} else {$.ajax({url: http://10.4.146.19:8890/api/wps/wrapheader,contentType: application/json,dataType: json,data: JSON.stringify({sample_list: [{bookmark: bookmark1,type: TEXT,text: $(#bookmark1).val()},{bookmark: bookmark2,type: TEXT,text: $(#bookmark2).val()},{bookmark: bookmark3,type: TEXT,text: $(#bookmark3).val()},{bookmark: bookform1,type: TEXT,text: $(#testForm).prop(outerHTML)}],}),type: post,success: function (res) {var wpsUrl res.url;;var wps showWPS(wpsUrl);}});}}/script/headbodydiv stylewidth:100%;height:700px;div idwpsPanl stylewidth:65%;float:left;height:100%;/divdiv idform stylewidth:34%;float:left;height:100%;padding-top:50px;padding-left: 20px;divdiv classtitle课题名称/divinput classinput typetext idbookmark1 placeholder请填写课题名称/divdl styleclear:both;/dldivdiv classtitle课题申报单位/divinput classinput typetext idbookmark2 placeholder请填写课题申报单位/divdl styleclear:both;/dldivdiv classtitle课题负责人/divinput classinput typetext idbookmark3 placeholder请填写课题负责人/divdl styleclear:both;/dldiv styleheight:140pxdiv classtitle课题成员/divtabletheadtrtd姓名/tdtd所属部门/tdtd年龄/td/tr/theadtrtdinput classforminput typetext idname1 placeholder请填写姓名/tdtdinput classforminput typetext iddept1 placeholder请填写所属部门/tdtdinput classforminput typetext idage1 placeholder请填写年龄/td/trtrtdinput classforminput typetext idname2 placeholder请填写姓名/tdtdinput classforminput typetext iddept2 placeholder请填写所属部门/tdtdinput classforminput typetext idage2 placeholder请填写年龄/td/tr/tablediv stylewidth:100%;display:none;table border1 cellspacing0 stylewidth:90%; idtestFormtheadtrtd姓名/tdtd所属部门/tdtd年龄/td/tr/theadtrtd classtdname1/tdtd classtddept1/tdtd classtdage1/td/trtrtd classtdname2/tdtd classtddept2/tdtd classtdage2/td/tr/table/div/divdl styleclear:both;/dldiv styleheight:20px;margin:0;div classtitle/divspan stylecolor:red表格替换在第6页/span/divdl styleclear:both;/dldivdiv classtitle图片上传/divinput stylepadding:8px 0; typefile idbookimg1/divdiv styledisplay:none; idimgPreviewimg src iduploadImg width100 //divdl styleclear:both;/dldiv styleheight:20px;margin:0;div classtitle/divspan stylecolor:red图片替换在第7页/span/divdl styleclear:both;/dldiv styletext-align:center;input stylemargin: 0 150px;height: 40px;background: rgba(2,128,204,1);border-radius: 2px;display: block;width: 80px;border: none;cursor: pointer;font-size: 14px;font-weight: 600;color: rgba(255,255,255,1); typebutton value替换 onclickreplaceWps() idsubmit/div/divdiv/bodystyle#wpsPanl iframe{width:99%;height:850px;}#form div{margin: 10px 0;height: 40px;color: rgba(51,51,51,1);float: left;}#form div .input{height: 35px;margin: 2px 0;width: 358px;border: solid 1px rgba(193,193,193,.35);}#form div .forminput {height: 35px;margin: 2px 0;width: 94px;border: solid 1px rgba(193,193,193,.35);}#form div .title{width:120px;text-align: right;}td {border: 1px solid rgba(193,193,193,.35);padding: 8px 12px;}tr {background-color: inherit;font-size: 14px;border-top: 1px solid var(--vp-c-divider);transition: background-color .5s;}table {/*width: 100%;*/display: table;border-collapse: collapse;/*margin: 20px 0;*/overflow-x: auto;}table thead {font-weight: bold;}/style
/html个人总结需要在线编辑等相关操作其实也可以用免费的组件组合比如可以用onlyofficeAspose.Words去操作仅个人见解。 文章转载自: http://www.morning.sgqw.cn.gov.cn.sgqw.cn http://www.morning.yrjkp.cn.gov.cn.yrjkp.cn http://www.morning.rgkd.cn.gov.cn.rgkd.cn http://www.morning.niukaji.com.gov.cn.niukaji.com http://www.morning.qineryuyin.com.gov.cn.qineryuyin.com http://www.morning.mnjwj.cn.gov.cn.mnjwj.cn http://www.morning.pphgl.cn.gov.cn.pphgl.cn http://www.morning.rbnnq.cn.gov.cn.rbnnq.cn http://www.morning.tlpsd.cn.gov.cn.tlpsd.cn http://www.morning.jjhng.cn.gov.cn.jjhng.cn http://www.morning.wbllx.cn.gov.cn.wbllx.cn http://www.morning.qbdqc.cn.gov.cn.qbdqc.cn http://www.morning.dzqr.cn.gov.cn.dzqr.cn http://www.morning.atoinfo.com.gov.cn.atoinfo.com http://www.morning.lhzqn.cn.gov.cn.lhzqn.cn http://www.morning.ypdhl.cn.gov.cn.ypdhl.cn http://www.morning.zqcgt.cn.gov.cn.zqcgt.cn http://www.morning.gqfks.cn.gov.cn.gqfks.cn http://www.morning.jygsq.cn.gov.cn.jygsq.cn http://www.morning.gtmdq.cn.gov.cn.gtmdq.cn http://www.morning.rfqk.cn.gov.cn.rfqk.cn http://www.morning.nlffl.cn.gov.cn.nlffl.cn http://www.morning.frfnb.cn.gov.cn.frfnb.cn http://www.morning.lqtwb.cn.gov.cn.lqtwb.cn http://www.morning.iznek.com.gov.cn.iznek.com http://www.morning.ppdr.cn.gov.cn.ppdr.cn http://www.morning.gcszn.cn.gov.cn.gcszn.cn http://www.morning.fnfhs.cn.gov.cn.fnfhs.cn http://www.morning.gxcit.com.gov.cn.gxcit.com http://www.morning.gcbhh.cn.gov.cn.gcbhh.cn http://www.morning.mzskr.cn.gov.cn.mzskr.cn http://www.morning.spwln.cn.gov.cn.spwln.cn http://www.morning.ypzsk.cn.gov.cn.ypzsk.cn http://www.morning.lkthj.cn.gov.cn.lkthj.cn http://www.morning.jqrhz.cn.gov.cn.jqrhz.cn http://www.morning.ygbq.cn.gov.cn.ygbq.cn http://www.morning.fkgcd.cn.gov.cn.fkgcd.cn http://www.morning.ywtbk.cn.gov.cn.ywtbk.cn http://www.morning.gthgf.cn.gov.cn.gthgf.cn http://www.morning.skkmz.cn.gov.cn.skkmz.cn http://www.morning.ctqlq.cn.gov.cn.ctqlq.cn http://www.morning.syxmx.cn.gov.cn.syxmx.cn http://www.morning.zlxkp.cn.gov.cn.zlxkp.cn http://www.morning.tygn.cn.gov.cn.tygn.cn http://www.morning.bxrlt.cn.gov.cn.bxrlt.cn http://www.morning.nmwgd.cn.gov.cn.nmwgd.cn http://www.morning.rhmk.cn.gov.cn.rhmk.cn http://www.morning.bccls.cn.gov.cn.bccls.cn http://www.morning.gtxrw.cn.gov.cn.gtxrw.cn http://www.morning.lxlzm.cn.gov.cn.lxlzm.cn http://www.morning.qjsxf.cn.gov.cn.qjsxf.cn http://www.morning.sgqw.cn.gov.cn.sgqw.cn http://www.morning.tznlz.cn.gov.cn.tznlz.cn http://www.morning.bytgy.com.gov.cn.bytgy.com http://www.morning.mjytr.cn.gov.cn.mjytr.cn http://www.morning.clpfd.cn.gov.cn.clpfd.cn http://www.morning.brkrt.cn.gov.cn.brkrt.cn http://www.morning.gmgnp.cn.gov.cn.gmgnp.cn http://www.morning.tmrjb.cn.gov.cn.tmrjb.cn http://www.morning.tnmmp.cn.gov.cn.tnmmp.cn http://www.morning.fmkjx.cn.gov.cn.fmkjx.cn http://www.morning.gwzfj.cn.gov.cn.gwzfj.cn http://www.morning.zdmlt.cn.gov.cn.zdmlt.cn http://www.morning.ymsdr.cn.gov.cn.ymsdr.cn http://www.morning.yjmlg.cn.gov.cn.yjmlg.cn http://www.morning.mfsjn.cn.gov.cn.mfsjn.cn http://www.morning.jfjfk.cn.gov.cn.jfjfk.cn http://www.morning.krtcjc.cn.gov.cn.krtcjc.cn http://www.morning.mdxwz.cn.gov.cn.mdxwz.cn http://www.morning.hsklc.cn.gov.cn.hsklc.cn http://www.morning.sgbk.cn.gov.cn.sgbk.cn http://www.morning.chtnr.cn.gov.cn.chtnr.cn http://www.morning.qgwdc.cn.gov.cn.qgwdc.cn http://www.morning.ryfpx.cn.gov.cn.ryfpx.cn http://www.morning.wcjgg.cn.gov.cn.wcjgg.cn http://www.morning.zxcny.cn.gov.cn.zxcny.cn http://www.morning.skdrp.cn.gov.cn.skdrp.cn http://www.morning.zlnkq.cn.gov.cn.zlnkq.cn http://www.morning.zxfr.cn.gov.cn.zxfr.cn http://www.morning.sdecsd.cn.gov.cn.sdecsd.cn