记一次文件因content-type问题无法打开的经历

2023-11-08

记一次文件因content-type问题无法打开的经历

在Http请求头和响应头都有这个attribute,来声明请求和响应报文的资源类型。

Content-Type(MediaType),即是Internet Media Type,互联网媒体类型,也叫做MIME类型。在互联网中有成百上千中不同的数据类型,HTTP在传输数据对象时会为他们打上称为MIME的数据格式标签,用于区分数据类型。最初MIME是用于电子邮件系统的,后来HTTP也采用了这一方案。
在HTTP协议消息头中,使用Content-Type来表示请求和响应中的媒体类型信息。它用来告诉服务端如何处理请求的数据,以及告诉客户端(一般是浏览器)如何解析响应的数据,比如显示图片,解析并展示html等等。

场景

我这边遇到的情况是,源文件的Content-Type全都显示为application/octet-stream,如PDF,PNG等,都显示这个,接着我们需要将这个文件上传到下游系统中,下游系统有另外的retrieve接口,来查看和下载这些文件。按照原逻辑,上传到下游系统的文件的Content-Type依旧会显示为application/octet-stream,部分终端使用这种格式下载下来是没什么问题的,能正确获取文件名,也能正常打开。问题出在某些终端对文件扩展名的解析方式不一样,通过mimeType去解析文件时,遇到application/octet-stream就会有问题,文件名可能就变成了xxx.bin。当然,这并不是我们所期望的。

方案

从源文件到下游系统,中间由我们系统集成,所以很理所当然想到在上传到下游系统之前,能否把这个Content-Type给它弄对。

Jsoup的Content-Type

查看了源代码,我们系统在上传文件到下游系统时,使用的是Jsoup三方依赖。这个接口需要同时上传文件和json文本,请求方式为POST。

文本参数用典型的kv参数方法

/**
     * Add a request data parameter. Request parameters are sent in the request query string for GETs, and in the
     * request body for POSTs. A request may have multiple values of the same name.
     * @param key data key
     * @param value data value
     * @return this Connection, for chaining
     */
    Connection data(String key, String value);

针对文件类型的参数,Jsoup提供了以下方法,可以设定文件名和文件输入流

    /**
     * Add an input stream as a request data parameter. For GETs, has no effect, but for POSTS this will upload the
     * input stream.
     * @param key data key (form item name)
     * @param filename the name of the file to present to the remove server. Typically just the name, not path,
     * component.
     * @param inputStream the input stream to upload, that you probably obtained from a {@link java.io.FileInputStream}.
     * You must close the InputStream in a {@code finally} block.
     * @return this Connections, for chaining
     * @see #data(String, String, InputStream, String) if you want to set the uploaded file's mimetype.
     */
    Connection data(String key, String filename, InputStream inputStream);

同时,我注意到Jsoup还提供了另外一个上传文件的方法,该方法支持设置文件的Content-Type

    /**
     * Add an input stream as a request data parameter. For GETs, has no effect, but for POSTS this will upload the
     * input stream.
     * @param key data key (form item name)
     * @param filename the name of the file to present to the remove server. Typically just the name, not path,
     * component.
     * @param inputStream the input stream to upload, that you probably obtained from a {@link java.io.FileInputStream}.
     * @param contentType the Content Type (aka mimetype) to specify for this file.
     * You must close the InputStream in a {@code finally} block.
     * @return this Connections, for chaining
     */
    Connection data(String key, String filename, InputStream inputStream, String contentType);

simplemagic

看到这里,我喜出望外,认为只需要根据源文件的inputStream来获取文件的Content-Type,设置到这个参数里就行了。在获取inputStream的Content-Type信息时,有很多选择,有原生的,也可以选择三方依赖,我这里选择的是simplemagic。

<dependency>
    <groupId>com.j256.simplemagic</groupId>
    <artifactId>simplemagic</artifactId>
    <version>1.17</version>
</dependency>

通过以下代码即可获取文件的Content-Type对象

ContentType contentType = new ContentInfoUtil().findMatch(file).getContentType();

该框架对输入提供了良好的支持,可以是文件路径,文件对象,文件流,也可以是byte数组。
在这里插入图片描述
按照这个思路,很快就完成了修改,本地postman测试,很快通过。

file can’t open

然而,按照上面描述的改动发版后,从下游系统下载的文件却无法打开。

通过postman调用下载接口,返回的内容可以预览(pdf格式,不得不说postman很强大),但是save response to file过后,文件却无法打开。这里有个小妙招,也是在工作中遇到的,有些打不开的pdf文件,如果使用类如edge等浏览器直接打开,打不开的话就直接报错打不开,如果用adobe尝试打开失败的话,会提示一些打不开的原因,如文件加密,文件格式损坏,文件破损等。这里我通过adobe打开发现是文件的file type有问题。
在这里插入图片描述

到这里,我怀疑过是我们下载接口的问题,但测试过直接从下游系统下载文件,文件依旧无法打开,那么问题只能出在我们将文件上传到下游系统的过程了。

我怀疑过Jsoup的传参方式是否正确,尝试过在文件头信息中加入Content-Type(因为我在debug的时候,看到入参的文件流是有头信息的,如postman上传,客户端上传等,都有),构建临时文件来转换等方法,均无一成功。首先,明确的是,通过simplemagic获取到的mimeType是对的,传到下游系统再反查出来回写到响应头里面的也是对的。

流不可重复消费问题

在处理文件打不开的过程,其实花费了许多时间,尝试的方式也很多,在上面没有一一列举。从下游系统下载的文件,通过simplemagic查看其Content-Type信息,为unkonwn,但文件后缀名是对的。这里需要说明一下,文件的mimeType判断方式有多种,扩展名是最常见也是不一定靠谱的一种。比如你创建一个text文件,强行将其扩展名修改为.pdf,再打开就会报错了,而且报的错和我这次遇到的报错一模一样。
在这里插入图片描述

在历经层层磨难后,终于发现了问题所在。

一个inputStream对象,我为了传获取它的Content-Type,其实已经消费了一次,在通过Jsoup上传到下游系统时,还是使用的是原来的那个流。再消费了一次后,再通过simplemagic去解析相同流的Content-Type时,你会发现结果就是unkonwn(第二次消费时,并没有报文件已关闭之类的异常)。至此,文件打不开的问题,就转换为处理流重复消费的问题了。直接跳转到针对流只能消费一次的处理方案就可以了,之前已经记录过,不再赘述。

通过这里的修改,文件便可以正常的上传,下载,预览,打开了。

Tika

和simplemagic类似,tika也是一个文件Content-Type解析的三方依赖,在处理问题的过程中,我也用过。经过测试,simplemagic对大部分文件支持良好,但csv文件却不行,而tika可以解析csv,但对office相关文件显得有些无能为力。所以最终使用二者结合来支持文件mimeType的判断。

<dependency>
    <groupId>org.apache.tika</groupId>
    <artifactId>tika-core</artifactId>
    <version>2.8.0</version>
</dependency>

总结

简单总结一下,在你我的开发生涯中,总会遇到一个又一个麻烦的问题(对当时的你会是个麻烦),可能你花了一些时间能够处理,并在过程中有所收获,也有可能你直接百度或csdn一搜就有了结果。领导可能在意的是处理了问题的结果,而对你个人成长,更重要的是处理问题的过程。

在刚出来工作的第一家公司,我们的一个服务总是会内存溢出,可用性极差。真正处理要处理这个问题可能需要花很多时间去排查测试(因为已经排查过业务代码的逻辑),领导建议做服务自动重启的工作,这样在一定程度能够缓解。对要求不算高的甲方,可能就糊弄过去了。但作为一个有洁癖的程序员,肯定不能接受这种是是而非的处理方式。后来通过层次排查,发现问题出来了三方依赖里面,问题才得到了真正的处理。

类似这样的问题还有很多,我也在CSDN的问答板块看到过许许多多折磨这程序员的问题,有些我已经经历过并掌握了,会觉得很简单,有一些是我还没曾在学习过程或项目中遇到过的,当我遇到了,也会头疼。所以,不断总结就显得非常重要了。

另外相对自己告诫的一点,查看处理问题时眼光不能太局限,定位问题比处理问题更重要。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

记一次文件因content-type问题无法打开的经历 的相关文章

  • Java中有没有一种方法可以通过名称实例化一个类?

    我正在寻找问题 从字符串名称实例化一个类 https stackoverflow com questions 9854900 instantiate an class from its string name它描述了如何在有名称的情况下实例
  • 如何让 BlazeDS 忽略属性?

    我有一个 java 类 它有一个带有 getter 和 setter 的字段 以及第二对 getter 和 setter 它们以另一种方式访问 该字段 public class NullAbleId private static final
  • 如何循环遍历所有组合,例如48 选择 5 [重复]

    这个问题在这里已经有答案了 可能的重复 如何在java中从大小为n的集合中迭代生成k个元素子集 https stackoverflow com questions 4504974 how to iteratively generate k
  • 如何使用assertEquals 和 Epsilon 在 JUnit 中断言两个双精度数?

    不推荐使用双打的assertEquals 我发现应该使用带有Epsilon的形式 这是因为双打不可能100 严格 但无论如何我需要比较两个双打 预期结果和实际结果 但我不知道该怎么做 目前我的测试如下 Test public void te
  • jQuery AJAX 调用 Java 方法

    使用 jQuery AJAX 我们可以调用特定的 JAVA 方法 例如从 Action 类 该 Java 方法返回的数据将用于填充一些 HTML 代码 请告诉我是否可以使用 jQuery 轻松完成此操作 就像在 DWR 中一样 此外 对于
  • 来自 dll 的 Java 调用函数

    我有这个 python 脚本导入zkemkeeperdll 并连接到考勤设备 ZKTeco 这是我正在使用的脚本 from win32com client import Dispatch zk Dispatch zkemkeeper ZKE
  • Java 公历日历更改时区

    我正在尝试设置 HOUR OF DAY 字段并更改 GregorianCalendar 日期对象的时区 GregorianCalendar date new GregorianCalendar TimeZone getTimeZone GM
  • 从最终实体获取根证书和中间证书

    作为密码学的菜鸟 我每天都会偶然发现一些简单的事情 今天只是那些日子之一 我想用 bouncy castle 库验证 java 中的 smime 消息 我想我几乎已经弄清楚了 但此时的问题是 PKIXparameters 对象的构建 假设我
  • 将流转换为 IntStream

    我有一种感觉 我在这里错过了一些东西 我发现自己做了以下事情 private static int getHighestValue Map
  • Hibernate 的 PersistentSet 不使用 hashCode/equals 的自定义实现

    所以我有一本实体书 public class Book private String id private String name private String description private Image coverImage pr
  • 在我的 Spring Boot 示例中无法打开版本 3 中的 Swagger UI

    我在 Spring Boot 示例中打开 swagger ui 时遇到问题 当我访问 localhost 8080 swagger ui 或 localhost 8080 root api name swagger ui 时出现这种错误 S
  • java for windows 中的文件图标叠加

    我正在尝试像 Tortoise SVN 或 Dropbox 一样在文件和文件夹上实现图标叠加 我在网上查了很多资料 但没有找到Java的解决方案 Can anyone help me with this 很抱歉确认您的担忧 但这无法在 Ja
  • Eclipse 选项卡宽度不变

    我浏览了一些与此相关的帖子 但它们似乎并不能帮助我解决我的问题 我有一个项目 其中 java 文件以 2 个空格的宽度缩进 我想将所有内容更改为 4 空格宽度 我尝试了 正确的缩进 选项 但当我将几行修改为 4 空格缩进时 它只是将所有内容
  • java.io.Serialized 在 C/C++ 中的等价物是什么?

    C C 的等价物是什么java io Serialized https docs oracle com javase 7 docs api java io Serializable html 有对序列化库的引用 用 C 序列化数据结构 ht
  • 最新的 Hibernate 和 Derby:无法建立 JDBC 连接

    我正在尝试创建一个使用 Hibernate 连接到 Derby 数据库的准系统项目 我正在使用 Hibernate 和 Derby 的最新版本 但我得到的是通用的Unable to make JDBC Connection error 这是
  • 使用反射覆盖最终静态字段是否有限制?

    在我的一些单元测试中 我在最终静态字段上的反射中遇到了奇怪的行为 下面是说明我的问题的示例 我有一个基本的 Singleton 类 其中包含一个 Integer public class BasicHolder private static
  • 使用 CXF-RS 组件时,为什么我们使用 而不是普通的

    作为后续这个问题 https stackoverflow com questions 20598199 对于如何正确使用CXF RS组件我还是有点困惑 我很困惑为什么我们需要
  • 如果没有抽象成员,基类是否应该标记为抽象?

    如果一个类没有抽象成员 可以将其标记为抽象吗 即使没有实际理由直接实例化它 除了单元测试 是的 将不应该实例化的基类显式标记为抽象是合理且有益的 即使在没有抽象方法的情况下也是如此 它强制执行通用准则来使非叶类抽象 它阻止其他程序员创建该类
  • 如何防止在Spring Boot单元测试中执行import.sql

    我的类路径中有一个 import sql 文件 其中包含一些 INSERT 语句 当使用 profile devel 运行我的应用程序时 它的数据被加载到 postgres 数据库中 到目前为止一切正常 当使用测试配置文件执行测试时 imp
  • Java中super关键字的范围和使用

    为什么无法使用 super 关键字访问父类变量 使用以下代码 输出为 feline cougar c c class Feline public String type f public Feline System out print fe

随机推荐

  • uni.navigateBack 传值

    uniapp使用uni navigateBack向上一个页面传值的方式 在需要传值的页面写 wx navigateBack 返回 delta 1 uni emit handClick 传递的参数名 传递的值 获取传过来的值在onShow里面
  • VC 运行时库 /MD、/MDd 和 /MT、/MTd

    VC 运行时库 MD MDd 和 MT MTd 2013 01 24 18 42 11058人阅读 评论 2 收藏 举报 分类 C C 19 有段时间在写cuda程序是出现过 error LNK2005 exit 已经在 MSVCRTD l
  • 微信小程序开发之——CSS动画

    一 概述 上一节介绍了通过CSS属性keyframes设置图片选择动画 本文介绍以下两种形式的动画 this animate 接口 旧的 wx createAnimation接口 新的 2 9 0开始支持 二 this animate 2
  • 数据安全之标准-规范-政策-报告 集合收藏

    下载连接 https note youdao com s Xu9Xu0Gz 20230815更新 DB T DB36 T 1713 2022 公共数据分类分级指南 江西 pdf DB31DSJ Z 005 2020 公共数据安全分级指南 上
  • linux系统上insar处理流程,[转载]linux下安装GAMMA软件

    1 保持网络连接状态 2 Linux编译环境安装 一般安装Linux软件前需要大量的库以及相关GNU软件 这样可以避免Linux软件安装或编译出错 将yum 代码复制进终端 若提示需root权限 则先获取root权限 如 cz localh
  • Android 删除文件或文件夹

    删除文件或文件夹 fun delFileOrDir file File if file exists return if file isDirectory 递归删除文件夹里的文件 file listFiles forEach delFile
  • 学生成绩管理系统

    学生实体 属性由学号 姓名 性别 出生日期 地区 民族组成 班级实体 属性由班级编码 班级名称 院系 年级 人数组成 课程实体 属性由课程号 课程名 学分 学时 学期 前置课组成 学时实体选择课程实体 属于多对多关系 学生事宜属于班级实体
  • Vue中使用vuex(五)

    vuex的模块化 命名空间 1 目的 让代码更好维护 让多种数据分类更加明确 2 创建person js import axios from axios import nanoid from nanoid export default na
  • C# Namespace详解

    我现在感到学好C 就是就是要知道C 的基本语法 C 的新的特点 C 能干什么 其中我感到不管如何 NAMESPACE都是很关键的 可以说不是只对C 而言 而是整个 NET都是由NAMESPACE组成的 所以我在看了C 的基本语法后 就直奔N
  • Android常用知识点总结

    一 选择题 1 Android项目中的主题和样式资源 通常放在 C 目录 A res drawable B res layout C res values D assets 2 Dalvik虚拟机属于Android系统架构中的 C A 应用
  • Torchvision.ops.batched_nms() 和 nms()区别

    区别 batched nms 根据每个类别进行过滤 只对同一种类别进行计算IOU和阈值过滤 nms 不区分类别对所有bbox进行过滤 如果有不同类别的bbox重叠的话会导致被过滤掉并不会分开计算 Torchvision ops nms 参数
  • 干货!人体姿态估计与运动预测

    点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入 我们人类具有识别人体姿态 预测短期未来的能力 例如在走路时我们会识别对向行人的姿态 根据对他们未来运动的预测来决定往左走还是往右走 在打篮球或踢足球时会根据对防守球员的姿态 运动
  • ASP.NET Core学习路线图

    说明 1 先决条件 C https www pluralsight com paths csharp Entity Framework https www pluralsight com search q entity 20framewor
  • 最新的ssm毕业设计题目50例

    ssm毕业设计题目1 10题 1 基于SSM的车险管理系统设计与实现 2 基于SSM框架的学子商城系统的设计与实现 3 基于SSM的高校排课系统的研究与应用 4 基于SSM的湖南省入境旅游客源市场结构分析 5 基于SSM模型的重庆制造业主导
  • VOSviewer安装及配置

    VOSviewer安装网址 VOSviewer Download 根据自己电脑安装 并且VOSviewer要求JAVA 使用的是1 8 0 https www oracle com technetwork java javase downl
  • 关于maven <dependencyManagement>标签的问题

    项目场景 我giao 大家好跟大家分享一个使用maven时发现的小问题 关于父工程pom文件中 dependencyManagement 标签的问题 问题描述 在新建夫工程pom文件时 在内部的依赖不会马上到中央仓库中去下载jar包 而是在
  • 李宏毅-DeepLearning-2017-Unsupervised Learning:Neighbor Embedding

    数据降维的方法 Manifold Learning 流行学习 1 什么是流形 流形学习的观点 认为我们所能观察到的数据实际上是由一个低维流行映射到高维空间的 由于数据内部特征的限制 一些高维中的数据会产生维度上的冗余 实际上这些数据只要比较
  • 将一台笔记本电脑作为另一台笔记本电脑的扩展显示器

    步骤 步骤1 打开设置 可以使用 快捷键win i 打开设置 然后点击 系统 步骤2 点击 投影到此电脑 可以看到右边的选项是灰色 不可以选 然后点击 可选功能 如果是可选的 可以跳过步骤4 步骤3 查找是否安装了 无线显示器 如果没有安装
  • 【机器学习】Tensorflow概率编程:线性混合模型

    线性模型是我们最常见到的 最理想的数学模型 基本的线性模型是数据科学入门的基本案例 然而现实生活中的线性问题 很大几率不适用于基本的线性模型 需要使用线性混合模型来描述 Tensorflow edward提供对这类问题的解决方案 大部分数据
  • 记一次文件因content-type问题无法打开的经历

    记一次文件因content type问题无法打开的经历 引 场景 方案 Jsoup的Content Type simplemagic file can t open 流不可重复消费问题 Tika 总结 引 在Http请求头和响应头都有这个a