一、PDF文档明明存在但Chrome浏览器预览却显示-未能加载PDF文档
通过程序上传了pdf文件到服务器上的minio对象存储中,上传成功也能在minio中查看到,但在浏览器中通过minio资源网址查看pdf文件时,提示未能加载PDF文档。不能正常显示。开始以为是浏览器的PDF插件问题,支持不够好,于是找了些JS插件,如PDFObject(https://pdfobject.com/ 实现在线嵌入PDF显示的方式。上面有很多显示样式可选,下面这项可以相关的地址如下:
PDFObject官网地址:https://pdfobject.com/#browser-support
其中一个全屏展示PDF的示例页面:https://pdfobject.com/examples/full-browser-default.html
可查看其源代码复制下来内容修改下路径:view-source:https://pdfobject.com/examples/full-browser-default.html
下载相应的css和js文件,将其代码精简后如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>PDFObject Example: Full-browser embed (no selector specified)</title>
<link href="./css/examples.css" rel="stylesheet" />
</head>
<body>
<div class="pdfobject-com"><a href="http://pdfobject.com">PDFObject.com</a></div>
<script src="./js/pdfobject.min.js"></script>
<script>
PDFObject.embed("url/to/pdf.pdf");
</script>
</body>
</html>
但是发现软件上传的pdf文件依然还是显示不了,而通过在浏览器直接向minio上传的文件都可以正常访问。通过web调用pdf记录可以看到此时HTTP状态码显示为206,Content type类型值不是pdf,通过浏览器上传的pdf文件调用时显示的是application/pdf。排查发现软件通过SDK上传文件到minio时有一个参数为Content type,其值被写死导致。
二、复习一下四种常见的POST提交数据方式
HTTP协议是以ASCII码传输,建立在TCP/IP协议之上的应用层规范。规范把 HTTP 请求分为三个部分:状态行、请求头、消息主体。协议规定 POST 提交的数据必须放在消息主体(entity-body)中,但协议并没有规定数据必须使用什么编码方式Content-Type。
服务端根据请求头(headers)中的Content-Type字段来获知请求中的消息主体是用何种方式编码,再对主体进行解析。所以说到POST提交数据方案,包含了Content-Type 和消息主体编码方式两部分。Content-Type的四种值分别代表四种方式,具体如下:
方式一:application/x-www-form-urlencoded
浏览器的原生form表单,如果不设置enctype属性,那么最终就会以 application/x-www-form-urlencoded方式提交数据。Content-Type被指定为application/x-www-form-urlencoded提交的数据按照key=val&key=val的方式进行编码,并且key和val都进行了URL转码。服务端例如 PHP 中,使用$_POST[′key′]可以获取到值。
方式二:multipart/form-data
常见的POST数据提交的方式。这种方式支持文件上传,不过必须要设置form的enctyped等于这个值。使用multipart/form-data方式会生成了一个boundary 来分割不同的字段,为了避免与正文重复,boundary是一段很长的随机拼接的字符串。然后Content-Type指明数据是以mutipart/form-data来编码并包括进本次请求的boundary 值。消息主体最后以 --boundary--标示结束。
方式三:application/json
由于JSON规范的流行,现在越来越多的开发者将application/json这个Content-Type作为响应头。用来告诉服务端消息主体是序列化后的JSON字符串。除了低版本IE之外各大浏览器都原生支持 JSON.stringify,服务端语言也都有处理JSON的函数,JSON能格式支持比键值对复杂得多的结构化数据,普通键值对中的值只能是字符串,而使用json,键值对可以重复嵌套。在服务端方面,使用php 不能通过$_POST从上面的请求中获得内容。这时需要判断请求头中Content-Type值,如果为 application/json时,则需要使用file_get_content从php://input里获得原始输入流,再json_decode 成对象。
方式四:text/xml
很久之前我使用过一回XML-RPC(XML Remote Procedure Call)。它是一种使用HTTP作为传输协议,XML作为编码方式的远程调用规范。不过后来使用很少。也许在十多年前,在json还未出来之前数据交互对接
总之application/x-www-form-urlencoded和multipart/form-data两种POST方式都是浏览器原生支持的,是普遍使用的两种方式,application/json是现在比较流行的新趋势。