HTTP首部——Content-Type的作用

article/2025/9/12 5:45:40

前言
对于我们习以为常的东西,却没有仔细思考它的作用。 HTTP的首部都各有个的价值,最近看到这个Content-Type,忽然让我想起来以前自己的一个小小的失误,而产生了一个bug。但是当时却搞得我焦头烂额,我在网络上查找了一圈也没有发现什么解决方案。最后,还是自己发现了写错的地方,而这个错误就是由于Content-Type所引起的。作为一名应用软件程序员,从计算机网络的角度来看,我们是工作在应用层的。所以对于应用层使用广泛的HTTP协议,还是要多了解一些。这样也有助于我们更好的理解应用,当出现我上面的这个问题时,可以很快的解决!

:虽然基本上不会遇到这个问题,因为Content-Type并不需要我们去管理,当时了解它的作用本身仍然是一件很有趣的事情!

请求报文的结构
在这里插入图片描述

github地址: https://github.com/crazy-dragon/simple_server
注:第一次在github里面创建仓库,感觉挺麻烦的,主要是网络实在是难以忍受,太慢了。感兴趣的就看看吧,不怎么会使用github,不过现在也在了解。

Content-Type 首部

先来看一下网络上对于MIME的介绍:

MIME(Multipurpose Internet Mail Extensions) 多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。它是一个互联网标准,扩展了电子邮件标准,使其能够支持:
非ASCII字符文本;非文本格式附件(二进制、声音、图像等);由多部分(multiple parts)组成的消息体;包含非ASCII字符的头信息(Header information)。 这个标准被定义在RFC 2045、RFC 2046、RFC 2047、RFC 2048、RFC 2049等RFC中。 MIME改善了由RFC 822转变而来的RFC 2822,这些旧标准规定电子邮件标准并不允许在邮件消息中使用7位ASCII字符集以外的字符。正因如此,一些非英语字符消息和二进制文件,图像,声音等非文字消息原本都不能在电子邮件中传输(MIME可以)。MIME规定了用于表示各种各样的数据类型的符号化方法。 此外,在万维网中使用的HTTP协议中也使用了MIME的框架,标准被扩展为互联网媒体类型。

所以MIME是帮助客户端自动使用指定的应用程序来处理传输来的文件,如果你使用过socket传输过文件,你就会明白了。通过网络传输的数据,是文件本身的二进制数据,当是但我们在计算机上使用文件时,它是具有特定的扩展名的,以便于使用特定的程序来打开它。可以设想这样一个问题:我通过socket向你发送了一幅图片,当是你却以为是一个文档。那么尝试打开并阅读它的努力都是白费的!或者是,有些人喜欢修改某些文件的扩展名,以逃避别人的检查。所以当你遇到一个位置扩展名或者没有扩展名的文件时,通常会使用打开为这个选项。这样来枚举一下各种可能性(大部分人都不了解这个,而且被隐藏的文件类型也很好猜出来。),多半就能试出来了。所以,可见文件的类型是多么的重要。

正是因为MIME在邮件中的广泛应用,所以HTTP协议直接就使用了它并做了一些扩展。HTTP报文中的 Content-Type 首部就是用来说明实体主体(报文的数据体)的MIME类型。它的值就是标准化的MIME类型,MIME类型由一个主媒体类型后面跟一条斜线以及一个子类型组成,子类型用于进一步描述媒体类型。

下面介绍几个常用的媒体类型:

媒体类型描述
text/html实体主体是HTML文档
text/plain实体主体是纯文本文档
image/jpeg实体主体是JPEG格式的图像
application/json实体主体是json
application/x-icon实体主体是ICO格式的图像
application/octet-stream实体是二进制数据(用于下载)

媒体的类型很多,这也构成了丰富的互联网世界。这里我只是选择了这几种来举例子,其它的只要需要使用时,再去查MIME表获取即可。

实际编程使用

Talk is cheap, show me your code!

上面都是一些理论性的介绍,下面让我们使用代码来实际使用上面介绍的几个首部的具体作用。这里提供一个小的demo用于演示,代码很简短。全部使用的原生代码,因为也就100多行,但是我觉得它还是很有趣的,用来学习HTTP的一些知识是很好的。

演示demo及介绍

目录结构

它非常简单,所以用来学习是再合适不过了,甚至不使用IDE都是可以的。
在这里插入图片描述
在这里插入图片描述
注: 这是我在resource文件夹下面存放的文件,如果想要运行的话,只要有这些同名的文件就行了。404.html、poem.html和json.txt也都一样。

demo功能

在IDE中启动项目后,打开浏览器:

访问路径功能
localhost:8888/返回主页
localhost:8888/poem.html返回主页
localhost:8888/no_poem.html返回不解析的html
localhost:8888/json返回json数据
localhost:8888/favicon返回网页的图标,多次访问,结果不同
localhost:8888/any.jpg以指定的格式下载二进制数据
other返回404页

代码

package dragon.httpserver;import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Random;public class DragonServer {public static final String CRLF = "\r\n";public static final String BLANK = " ";private static final int BOUND = 7;private int port;public DragonServer(int port) {this.port = port;}public static void main(String[] args) throws IOException {System.out.println("The server has started...");new DragonServer(8888).start();}public void start() {try (ServerSocket server = new ServerSocket(port)) {while (true) {Socket client = server.accept();new Thread(()-> {try {// 获取输入流InputStream in = new BufferedInputStream(client.getInputStream());// 获取输出流OutputStream out = new BufferedOutputStream(client.getOutputStream());// 读取报文第一行,即请求行StringBuilder requestLine = new StringBuilder();// 我这里只读一行,不读取全部报文,程序没有报错!这是为什么?while (true) {int c = in.read();if (c == '\r' || c == '\r' || c == -1) break;// 不要直接使用 char 去读取,因为读取到结束的 -1 会转成 65535,导致后序的判断失败!requestLine.append((char)c);}// 这里有一个奇怪的问题,线程没有读取到任何数据,我这几就直接返回它了!if (requestLine.length() == 0) {return ;}String line = requestLine.toString();String[] lines = line.split(" ");System.out.println("request line: --> " + line);String method = lines[0];String path = lines[1];String protocol = lines[2];System.out.println("request method: " + method);System.out.println("request path: " + path);System.out.println("request protocol: " + protocol);// 设置一个标志变量,如果为 1,就默认为 Content-Type: plain/html,否则为其它的Path filepath = null;String contentType = null;String statusLine = "200 OK";// 路由分发switch (path) {case "/":case "/poem.html": filepath = Paths.get("./resource", "poem.html");contentType = "text/html;charset=UTF-8";break;case "/no_poem.html":filepath = Paths.get("./resource",  "poem.html");contentType = "text/plain;charset=UTF-8";         // 区别在这里!浏览器不会解析该 html !break;case "/json":filepath = Paths.get("./resource", "json.txt");contentType = "application/json;charset=UTF-8";   // 虽然它的功能和 text/plain 相似,但是表示的范围更小!break;case "/favicon.ico": Random rand = new Random();String name = "favicon" + rand.nextInt(BOUND) + ".ico";filepath = Paths.get("./resource", name);contentType = "image/x-icon";      // 写错成了 image/x-ico 变成自动下载了!break;case "/any":filepath = Paths.get("./resource", "404.html");  contentType = "application/octet-stream";    // 这个首部非常有趣,当是对于它的介绍很少。break;default: filepath = Paths.get("./resource",  "404.html");statusLine = "404 Not Found";contentType = "text/html;charset=UTF-8";         // plain/html 会自动下载了,奇怪!break;}StringBuilder headerBuilder = new StringBuilder();byte[] entity = Files.readAllBytes(filepath);		// 构造响应头headerBuilder.append("HTTP/1.0").append(BLANK).append(statusLine).append(CRLF).append("Server:").append(BLANK).append("dragon 1.0").append(CRLF).append("Content-Length:").append(BLANK).append(entity.length).append(CRLF).append("Content-Type:").append(BLANK).append(contentType).append(CRLF).append(CRLF);// 输出响应头System.out.println(headerBuilder);byte[] header = headerBuilder.toString().getBytes(StandardCharsets.UTF_8);out.write(header);out.write(entity);out.flush();   // 一定要显示刷新流,防止出错!} catch (IOException e) {e.printStackTrace();} finally {try {if (client != null) {client.close();}} catch (IOException e) {e.printStackTrace();}}}).start();}} catch (IOException e) {e.printStackTrace();}}
}

演示

1.访问根目录
注意:我的程序是带有图标的!但是浏览器缓存了该图标,导致了它似乎不会变化了,尽管我是加入了变化的。因为第一次访问一个新的url的时候,浏览器会发出两个请求。一个是用户请求,另一个是请求该网站的ico图标。
在这里插入图片描述

我这里这是简单的获取请求行的信息,其它的都丢弃了。但是这里并没有请求图标的请求信息,应该是图标被缓存了,所以就不会再次请求了。网站的图标一般都是固定不变的,它是品牌的代表。
request line: --> GET / HTTP/1.1
在这里插入图片描述
说明
这里返回类型是 Content-Type: text/html,它告诉浏览器响应为一个html文档,所以浏览器会自动解析它。所以,你不要以为只要返回的是html页面,浏览器就会解析它。因为浏览器其实没有那么智能!


2.访问 /poem.html
这个结果和访问 / 是一样的,不做过多介绍,看上面即可!
在这里插入图片描述


3.访问 /no_poem.html
在这里插入图片描述
在这里插入图片描述
说明:
这个返回的类型是:Content-Type: text/plain,它表示的是纯文本文件。所以浏览器只是会展示它,而不是去解析它。因为html文档本身也是纯文本,所以浏览器只是单纯的显示它的内容而已。这里就引出了我开头所述的问题,我将返回html页面的首部写错了,本来是 text/html,结果写成了 text/plain。导致我的页面浏览器不解析,我遇到这个问题真是一脸懵逼。网络上也没有找到答案,因为大家都是使用现有的Web服务器,所以几乎不会遇到这种问题。后来,找了很久才发现是这里出错了。不过倒也是因此对Content-Type有了一些认识。


4.访问 /json
在这里插入图片描述
说明:
返回一个简单的json数据,这个是应用很广泛的了,现在流行使用json来传递数据(xml在数据传输上基本上很少使用了)。最近看到一句王阳明的话,觉得非常有趣。于是就写进去了和大家分享一下:此心光明,亦复何言。 它的 Content-Type 是 application/json,但是从效果上来看似乎和 text/plain 没有什么区别。确实也是,即使换成 text/plain 也是没有问题的。但是它表示的更加精确,对于应用程序来说更加友好。


5.访问 /favicon.ico
这个路径基本上任何一个网站都有的,所以你可以到任何一个网站的根目录后面加上该路径进行访问,查看它们的图标。还有一个路径是 /robots.txt,该路径基本上正规的网站也都有,它是一个爬虫的道德约束文件。

这里举一个例子,所以网站要有一个简单好认的图标,提高识别度。
在这里插入图片描述

我自己demo的图标:
我特意玩了一个小技巧,弄了一个随机访问的图标(总共有7个图标)。但是由于浏览器会缓存,导致它没有多少用处了。但是你还是可以通过多次访问路径,查看不同的图标。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
注意:
最好不要使用黑色风格的图标,因为整个背景是黑色的,黑+黑就会遮盖了很多东西,我有一个图标是一个黑色的龙,结果只剩下一个全黑的背景了。哈哈!


6.访问 /any.jpg
在这里插入图片描述
在这里插入图片描述

说明:
这个返回的类型是:Content-Type: application/octet-stream,它表示某种二进制数据,浏览器会立刻进行下载,而下载的文件的名字,就是最后的路径名。并且,如果你写错了 Content-Type,或者不写 Content-Type,浏览器都会进行下载操作。似乎,它就是默认的Content-Type。并且,在postman中,发送请求时,如果是文件的话,可以选择body的类型为 binary。它就是表示使用该首部。

注意:当我编写这个程序时,我一开始没有看MIME表,直接凭借着感觉写Content-Type,但是写错了。访问某个路径直接变成下载了。真是一个大坑!不过现在反而也更加明白了它的作用。
在这里插入图片描述


7.访问任何其它路径
在这里插入图片描述

总结

如果看了这篇博客,并且实际运行我的代码,相信你会对 Content-Type 有一个全新的理解。它真的挺有趣的,学习这些协议的知识,对于我们以后的开发也是很重要的。特别是很多需要使用到协议的工作,例如网络数据采集(爬虫),对于请求头的分析其实是必不可少的。所以,基础知识的掌握是很重要的!


http://chatgpt.dhexx.cn/article/H0Q5wSiD.shtml

相关文章

http(S)系列之(一):概念

参考文章: HTTP & HTTPS网络协议重点总结(基于SSL/TLS的握手、TCP/IP协议基础、加密学) 一篇比较全的HTTP协议详解 记:千万别误会,本章是完全ctrlc然后ctrlv,知识理解才是最重要,不必要在…

http 协议之 Content-Type

Content-Type 字段是 http 服务端返回给客户端时,head 里面带上的,这个字段表明服务端返回给客户端的 body 是什么类型的,然后客户端就可以根据这个类型进行文件处理。如浏览器客户端,针对 text/html 类型时,是直接显示…

Http中的Content-Type详解

Content-Type Content-Type(MediaType),即是Internet Media Type,互联网媒体类型,也叫做MIME类型。在互联网中有成百上千中不同的数据类型,HTTP在传输数据对象时会为他们打上称为MIME的数据格式标签&#x…

HTTP(S)协议详解

1 什么是协议 协议,网络协议的简称,网络协议是通信计算机双方必须共同遵从的一组约定。如怎么样建立连接、怎么样互相识别等。只有遵守这个约定,计算机之间才能相互通信交流。 粗俗理解协议就是 比如你的电脑和我的电脑要通信,&a…

详解Http的Content-Type

目录 1.概述 2.常用类型 2.1.application/x-www-form-urllencoded 2.2.application/json 3.Spring MVC支持的编码 3.1.实验 3.2.适配器 3.3.自定义适配器 1.概述 HTTP(HyperText Transfer Protocol),超文本传输协议。超文本&#xf…

Http协议之Content-Type理解

Content-Type,翻译过来就是”内容类型“,在互联网中就是”互联网媒体类型“。 在互联网中,两台计算机经常会传输数据,客户端会给服务器发数据,服务器也会给客户端发数据。数据的类型也是有很多种的,我们把所…

tomcat修改jdk配置两种方法

由于一个电脑多个项目,可能会使用多个版本的jdk,所以在跑tomcat的时候,可以自定义配置的各项目所使用的jdk 配置步骤(window设置): 1. 在catalina.bat找到如下代码: echo Using JAVA_HOME: “%JAVA_HOME%” 替换成 echo Using JAVA_HOME: “E:\Company\Tool\jdk1.7.0_13” 如…

linux下jdk配置

一、jdk下载 jdk下载地址:https://www.oracle.com/java/technologies/downloads/ 二、配置环境变量 1、解压 tar -xvf jdk-11.0.13_linux-x64_bin.tar.gz 2、配置环境变量 修改/etc/profile文件 vim /etc/profile 文件末尾添加 #jdk JAVA_HOME/usr/local/a…

Mac多JDK配置

Mac多JDK配置 开发环境有时候需要配置多个JDK,Windows下配置比较方便,Mac环境下稍微有点曲折 下载对于的JDK 这里我以JDK8、JDK11为例,可以从oracle官网下载,也可以从国内源下载,比如华为源 直接安装后 执行如下命令可以快速…

eclipse及jdk配置

JDK(Java Development Kit)是Sun Microsystems针对Java开发员的产品。自从Java推出以来,JDK已经成为使用最广泛的Java SDK。JDK 是整个Java的核心,包括了Java运行环境,Java工具和Java基础的类库。JDK是学好Java的第一步。而专门运行在x86平台…

JDK配置Path的详细教程(包教包会)

在教程之前,先提示一下,新版本的JDK(比如17)是不需要我们配置的,因为我们在下载的时候已经自动给我们配置了,但是老版本(比如JDK8)是需要我们自己去配置的 OK,进入正题,我们先来说一下为什么要给jdk配置path环境? 首先,我们需要清楚的是jdk是java的开发工具,运行一个java程序…

多jdk配置

1.这里默认安装好jdk8和对应的环境变量,本文我们把jdk8的环境修改为jdk17(安装jdk17,下载安装版jdk17一直点下一步就行,没有好讲的) 2.系统CLASSPATH变量值为(下面都是在系统变量位置进行操作): .;%JAVA_HOME%\bin;%JAVA_HOME%\lib\tools.jar;%JAVA_HO…

Mac开发环境jdk配置

第一步: 下载JDK oracle 官网下载jdk版本 阿里云分享了已经在官方下载好的jdk8 阿里云盘分享https://www.aliyundrive.com/s/pNhjrrG3Pxf密码:8q8f 第二步骤:打开终端 第三步骤 :执行命令 查看JDK下载路径 执行命令:…

java中的jdk配置详解:

java中的jdk配置详解: 1.配值系统变量"JAVA_HOME" 变量名JAVA_HOME: 指向:JDK(java开发工具包)的安装路径 目的:使用JDK安装目录时,可以直接通过”%JAVA_HOME%“访问,避免路径过长麻烦 归一原则&#xff…

JAVA-JDK配置说明

JDK开发环境配置说明 JDK原理 JDK配置JDK与JRE区别 JDK下载地址 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html (注意查看本地电脑的版本,对应相同的系统,选择下载jdk) 目录 JDK开发环境配置说明 JDK下载地址…

jdk配置环境变量(win10)

jdk配置环境变量(win10) jdk跟环境变量的配置是学习java的必经之路!你是否已经掌握呢? 1.下载安装jdk 官网下载:https://www.oracle.com/cn/java/technologies/downloads/#java8-windows 如果是要下载1.8版本的话,也可以用百度云…

linux JDK配置

1.JDK安装与配置 一般而言,Ubuntu系统会自带JDK,如果没有或者版本不合要求,可按以下步骤进行安装。步骤1 安装JDK。 步骤1 安装JDK。 将下载的.bin文件复制到Linux的某个目录下,比如/usr/lib/jvm/,然后在Shell中执行…

eclipse安装及jdk配置

一:eclipse的下载与安装 1、首先我们进入eclipse下载官网进行下载,链接为: Eclipse Downloads | The Eclipse Foundation 2、我们点击Download Packages选择其他类型的下载包: 3、Eclipse IDE for Java Developers 该版本适合Ja…

jdk配置环境变量

1.安装jdk,从官网下就行,我的是把原来的做了个备份,直接解压的。如下图 2.记录下你要配置的jdk路径。右键此电脑,属性,点击高级系统设置,选择环境变量。 3.现在就可以新建环境变量了。点击新建,…

JDK的安装与配置(含配置多个JDK)

对于Java学习者来说,一台电脑拿到手肯定要配置JDK,但是对于新手来说还是容易出错,我也是在安装了好几次之后才熟练,最近已经不满足JDK8了,想要配置多个JDK切换使用,所以写篇文章记录一下,希望也…