HTML实现在线预览Excel,word,ppt

使用office提供的在线预览功能
https://view.officeapps.live....
src后面接你需要预览的文件下载地址.
如果不能实现预览功能,提示报错
clipboard.png
请检查http返回的Content-Type是否正确

当从浏览器返回一个文件时,需要指定ContentType,以下是Office2007对应的值:
"application/vnd.openxmlformats-officedocument.wordprocessingml.template" (for .dotx files)
"application/vnd.openxmlformats-officedocument.presentationml.presentation" (for .pptx files)
"application/vnd.openxmlformats-officedocument.presentationml.slideshow" (for .ppsx files)
"application/vnd.openxmlformats-officedocument.presentationml.template" (for .potx files)
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" (for .xlsx files)
"application/vnd.openxmlformats-officedocument.spreadsheetml.template" (for .xltx files)

参考链接:

https://www.cnblogs.com/huang...
office在线预览文档: https://products.office.com/z...
office文件对应的contentType: https://www.cnblogs.com/diony...

bug解决记录:

原来网站中有个需要,是下载Excel.
最开始实现的时候,是使用jsreport来实现,但是该服务收费,并且由于功能太强大了,学习成本高.

因为我们只是想要下载Excel,后面就找了Excel.js这个库来实现.

下载Excel是没问题,生成文件流以后,,直接返回steam,有一天,领导说,需要在线预览Excel?
考虑过几种方案,

  1. 自己实现解析Excel,直接以表格的样式返回HTML
  2. 找第三方js库,来实现Excel预览,
  3. 其他(尽可能少改动现有代码)

在找其他方案的时候,发现,其他Microsoft Office365提供了在线预览的功能,只需要
https://view.officeapps.live....
src后面跟上Excel的下载地址就行.

但是测试了一下,发现并不能成功.因为我们服务器上通过接口下载Excel的URL拼接在上面src后面,不能预览,会报错.

但是,如果是访问静态资源目录,拼接在src后面,是可以的.
比如: http://a.com/excel.xlsx 可以在线预览
https://a.com/download/report... 不能在线预览
我就怀疑是response Header设置问题,但是,不清楚具体是哪个配置项.

最开始以为是https的问题,但是测试后发现,与https无关,https和http协议都能在线预览
也考虑过是不是URL上没用后缀,导致office无法识别该文件是什么类型,但是下载保存的时候,会自动识别出对应的文件后缀名,所以就肯定不是URL上没有后缀名导致的问题.
服务器后端使用的是Node.js,框架用的是express,如果将Excel放置在静态资源文件目录下,是能正常预览.
如果是将文件放在静态资源文件夹下访问,等同于调用express中的res.sendFile(filePath)方法.
我们的接口中,使用

res.set({
    'Content-Disposition': 'Attachment; filename="report.xlsx'
});

来设置response的header,保证用户下载文件后存储到本地时默认是Excel后缀.

好,因为基础知识不牢,只能去查看express的源码中sendFile()方法有什么奥秘了
node_modules/express/lib/response.js

res.sendFile = function sendFile(path, options, callback) {
  var done = callback;
  var req = this.req;
  var res = this;
  var next = req.next;
  var opts = options || {};

  if (!path) {
    throw new TypeError('path argument is required to res.sendFile');
  }

  // support function as second arg
  if (typeof options === 'function') {
    done = options;
    opts = {};
  }

  if (!opts.root && !isAbsolute(path)) {
    throw new TypeError('path must be absolute or specify root to res.sendFile');
  }

  // create file stream
  var pathname = encodeURI(path);
  var file = send(req, pathname, opts);

  // transfer
  sendfile(res, file, opts, function (err) {
    if (done) return done(err);
    if (err && err.code === 'EISDIR') return next();

    // next() all but write errors
    if (err && err.code !== 'ECONNABORTED' && err.syscall !== 'write') {
      next(err);
    }
  });
};

可以看到,实际上sendFile调用的是node_modules/send/index.js方法,
在看send模块中的代码,发现

var mime = require('mime')

SendStream.prototype.type = function type (path) {
  var res = this.res

  if (res.getHeader('Content-Type')) return

  var type = mime.lookup(path)

  if (!type) {
    debug('no content-type')
    return
  }

  var charset = mime.charsets.lookup(type)

  debug('content-type %s', type)
  res.setHeader('Content-Type', type + (charset ? '; charset=' + charset : ''))
}

express在发送文件时,会调用上述代码,根据后缀名来获取Content-Type.
在查看mime的源码,会发现在mime中,require了一个type.json,而type.json就是各种后缀名对应的content-type

因为我们原来的代码中,只设置了Content-Disposition,代表该请求返回的是一个文件.
但是office365实际上是通过Content-Type来获取,当前需要预览的是什么类型的文件(word,ppt,Excel),所以,需要设置对应的Content-Type才能正确实现预览功能

mime库中type.json中后缀名对应的ContentType,可以用来做速查表

{
  "application/andrew-inset": [
    "ez"
  ],
  "application/applixware": [
    "aw"
  ],
  "application/atom+xml": [
    "atom"
  ],
  "application/atomcat+xml": [
    "atomcat"
  ],
  "application/atomsvc+xml": [
    "atomsvc"
  ],
  "application/bdoc": [
    "bdoc"
  ],
  "application/ccxml+xml": [
    "ccxml"
  ],
  "application/cdmi-capability": [
    "cdmia"
  ],
  "application/cdmi-container": [
    "cdmic"
  ],
  "application/cdmi-domain": [
    "cdmid"
  ],
  "application/cdmi-object": [
    "cdmio"
  ],
  "application/cdmi-queue": [
    "cdmiq"
  ],
  "application/cu-seeme": [
    "cu"
  ],
  "application/dash+xml": [
    "mpd"
  ],
  "application/davmount+xml": [
    "davmount"
  ],
  "application/docbook+xml": [
    "dbk"
  ],
  "application/dssc+der": [
    "dssc"
  ],
  "application/dssc+xml": [
    "xdssc"
  ],
  "application/ecmascript": [
    "ecma"
  ],
  "application/emma+xml": [
    "emma"
  ],
  "application/epub+zip": [
    "epub"
  ],
  "application/exi": [
    "exi"
  ],
  "application/font-tdpfr": [
    "pfr"
  ],
  "application/font-woff": [
    "woff"
  ],
  "application/font-woff2": [
    "woff2"
  ],
  "application/geo+json": [
    "geojson"
  ],
  "application/gml+xml": [
    "gml"
  ],
  "application/gpx+xml": [
    "gpx"
  ],
  "application/gxf": [
    "gxf"
  ],
  "application/gzip": [
    "gz"
  ],
  "application/hyperstudio": [
    "stk"
  ],
  "application/inkml+xml": [
    "ink",
    "inkml"
  ],
  "application/ipfix": [
    "ipfix"
  ],
  "application/java-archive": [
    "jar",
    "war",
    "ear"
  ],
  "application/java-serialized-object": [
    "ser"
  ],
  "application/java-vm": [
    "class"
  ],
  "application/javascript": [
    "js",
    "mjs"
  ],
  "application/json": [
    "json",
    "map"
  ],
  "application/json5": [
    "json5"
  ],
  "application/jsonml+json": [
    "jsonml"
  ],
  "application/ld+json": [
    "jsonld"
  ],
  "application/lost+xml": [
    "lostxml"
  ],
  "application/mac-binhex40": [
    "hqx"
  ],
  "application/mac-compactpro": [
    "cpt"
  ],
  "application/mads+xml": [
    "mads"
  ],
  "application/manifest+json": [
    "webmanifest"
  ],
  "application/marc": [
    "mrc"
  ],
  "application/marcxml+xml": [
    "mrcx"
  ],
  "application/mathematica": [
    "ma",
    "nb",
    "mb"
  ],
  "application/mathml+xml": [
    "mathml"
  ],
  "application/mbox": [
    "mbox"
  ],
  "application/mediaservercontrol+xml": [
    "mscml"
  ],
  "application/metalink+xml": [
    "metalink"
  ],
  "application/metalink4+xml": [
    "meta4"
  ],
  "application/mets+xml": [
    "mets"
  ],
  "application/mods+xml": [
    "mods"
  ],
  "application/mp21": [
    "m21",
    "mp21"
  ],
  "application/mp4": [
    "mp4s",
    "m4p"
  ],
  "application/msword": [
    "doc",
    "dot"
  ],
  "application/mxf": [
    "mxf"
  ],
  "application/octet-stream": [
    "bin",
    "dms",
    "lrf",
    "mar",
    "so",
    "dist",
    "distz",
    "pkg",
    "bpk",
    "dump",
    "elc",
    "deploy",
    "exe",
    "dll",
    "deb",
    "dmg",
    "iso",
    "img",
    "msi",
    "msp",
    "msm",
    "buffer"
  ],
  "application/oda": [
    "oda"
  ],
  "application/oebps-package+xml": [
    "opf"
  ],
  "application/ogg": [
    "ogx"
  ],
  "application/omdoc+xml": [
    "omdoc"
  ],
  "application/onenote": [
    "onetoc",
    "onetoc2",
    "onetmp",
    "onepkg"
  ],
  "application/oxps": [
    "oxps"
  ],
  "application/patch-ops-error+xml": [
    "xer"
  ],
  "application/pdf": [
    "pdf"
  ],
  "application/pgp-encrypted": [
    "pgp"
  ],
  "application/pgp-signature": [
    "asc",
    "sig"
  ],
  "application/pics-rules": [
    "prf"
  ],
  "application/pkcs10": [
    "p10"
  ],
  "application/pkcs7-mime": [
    "p7m",
    "p7c"
  ],
  "application/pkcs7-signature": [
    "p7s"
  ],
  "application/pkcs8": [
    "p8"
  ],
  "application/pkix-attr-cert": [
    "ac"
  ],
  "application/pkix-cert": [
    "cer"
  ],
  "application/pkix-crl": [
    "crl"
  ],
  "application/pkix-pkipath": [
    "pkipath"
  ],
  "application/pkixcmp": [
    "pki"
  ],
  "application/pls+xml": [
    "pls"
  ],
  "application/postscript": [
    "ai",
    "eps",
    "ps"
  ],
  "application/prs.cww": [
    "cww"
  ],
  "application/pskc+xml": [
    "pskcxml"
  ],
  "application/rdf+xml": [
    "rdf"
  ],
  "application/reginfo+xml": [
    "rif"
  ],
  "application/relax-ng-compact-syntax": [
    "rnc"
  ],
  "application/resource-lists+xml": [
    "rl"
  ],
  "application/resource-lists-diff+xml": [
    "rld"
  ],
  "application/rls-services+xml": [
    "rs"
  ],
  "application/rpki-ghostbusters": [
    "gbr"
  ],
  "application/rpki-manifest": [
    "mft"
  ],
  "application/rpki-roa": [
    "roa"
  ],
  "application/rsd+xml": [
    "rsd"
  ],
  "application/rss+xml": [
    "rss"
  ],
  "application/rtf": [
    "rtf"
  ],
  "application/sbml+xml": [
    "sbml"
  ],
  "application/scvp-cv-request": [
    "scq"
  ],
  "application/scvp-cv-response": [
    "scs"
  ],
  "application/scvp-vp-request": [
    "spq"
  ],
  "application/scvp-vp-response": [
    "spp"
  ],
  "application/sdp": [
    "sdp"
  ],
  "application/set-payment-initiation": [
    "setpay"
  ],
  "application/set-registration-initiation": [
    "setreg"
  ],
  "app
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值