JAVA:利用 Content Negotiation 实现多样式响应格式的技术指南
1、简述
Content Negotiation(内容协商) 是 RESTful 服务的重要特性,允许客户端和服务器根据请求的不同特性动态选择适合的响应格式。它是一种在 HTTP 协议中实现的机制,通过它,服务器能够根据客户端需求返回适合的内容类型(如 JSON、XML、HTML)。
本文将介绍 Content Negotiation 的原理、实现方式,并通过详细示例演示其在 Spring Boot 中的实际应用。

2、原理
Content Negotiation 的核心在于客户端通过 HTTP 请求头中的 Accept、Content-Type 等字段,告知服务器它支持的内容格式,而服务器根据这些信息返回匹配的内容。以下是主要的 HTTP 头字段:
- Accept:指定客户端希望接受的内容类型。例如:
Accept: application/json
表示客户端希望接收到 JSON 格式的响应。
-
Content-Type:指定请求体的内容格式(如 POST 请求的 JSON 数据)。
-
Accept-Language:指定客户端支持的语言。
Content Negotiation 有以下三种常见实现方式:
-
HTTP Header-Based Negotiation(基于请求头的协商)
客户端通过 Accept 头告知服务器期望的响应类型。
示例:Accept: application/xml。 -
URL Path-Based Negotiation(基于 URL 路径的协商)
通过扩展名直接指定期望的响应类型。
示例:/api/resource.json。 -
Query Parameter-Based Negotiation(基于查询参数的协商)
客户端通过查询参数指定期望的响应类型。
示例:/api/resource?format=json。
3、Content Negotiation 实现
Spring Boot 提供了对 Content Negotiation 的内置支持,可以轻松实现多种响应格式。
3.1 添加必要的依赖
确保你的项目中已经包含以下依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId>
</dependency>
3.2 配置 Content Negotiation
在 Spring Boot 中,通过 ContentNegotiationConfigurer 配置支持的内容协商方式:
package com.example.springbootclient.config;import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void configureContentNegotiation(ContentNegotiationConfigurer configurer) {configurer// 支持 URL 后缀形式,如 .json 或 .xml.favorPathExtension(true)// 支持查询参数,如 ?format=json 或 ?format=xml.favorParameter(true).parameterName("format")// 如果未指定,则根据请求头返回内容类型.ignoreAcceptHeader(false).useRegisteredExtensionsOnly(false)// 默认返回 JSON.defaultContentType(MediaType.APPLICATION_JSON)// 注册媒体类型.mediaType("json", MediaType.APPLICATION_JSON).mediaType("xml", MediaType.APPLICATION_XML);}
}
3.3 创建示例控制器
创建一个简单的 REST 控制器,用于返回多种格式的数据:
package com.example.springbootclient.controller;import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;
import java.util.Map;@RestController
@RequestMapping("/api")
public class ContentNegotiationController {@GetMapping(value = "/resource")public ResponseEntity<Object> getResource() {Map<String, String> data = new HashMap<>();data.put("id", "1");data.put("name", "Content Negotiation Example");return ResponseEntity.ok(data);}@GetMapping(value = "/resource.{format}", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})public ResponseEntity<Object> getFormat() {Map<String, String> data = new HashMap<>();data.put("id", "1");data.put("name", "Content Negotiation Example");return ResponseEntity.ok(data);}
}
4、详细样例
以下是几种 Content Negotiation 的请求和响应示例:
4.1 基于 HTTP 请求头
请求:
GET /api/resource HTTP/1.1
Host: localhost:8080
Accept: application/json
响应:
{"id": "1","name": "Content Negotiation Example"
}
如果请求头为 Accept: application/xml,响应为:
<HashMap><name>Content Negotiation Example</name><id>1</id>
</HashMap>
4.2 基于 URL 路径扩展名
请求:
GET /api/resource.json HTTP/1.1
Host: localhost:8080
响应:
{"id": "1","name": "Content Negotiation Example"
}
请求:
GET /api/resource.xml HTTP/1.1
Host: localhost:8080
响应:
<HashMap><name>Content Negotiation Example</name><id>1</id>
</HashMap>
4.3 基于查询参数
请求:
GET /api/resource?format=json HTTP/1.1
Host: localhost:8080
响应:
{"id": "1","name": "Content Negotiation Example"
}
请求:
GET /api/resource?format=xml HTTP/1.1
Host: localhost:8080
响应:
<HashMap><name>Content Negotiation Example</name><id>1</id>
</HashMap>
5、Content Negotiation 的优缺点
5.1 优点:
- 客户端可以灵活选择所需的内容格式。
- 支持多种协商方式,适用性广。
- 降低了为不同格式创建独立 API 的复杂性。
5.2 缺点:
- 配置较为复杂,可能导致意外的行为。
- 扩展名协商可能不符合 RESTful API 的最佳实践。
- 对 Accept 头的支持可能不一致。
6、总结
Content Negotiation 是 RESTful API 中的重要功能,能够为客户端提供更好的灵活性。在 Spring Boot 中,Content Negotiation 的实现非常灵活,支持多种协商方式。通过合理的配置和设计,可以实现更加优雅和高效的服务接口。希望本文对你理解 Content Negotiation 的核心原理和实现有所帮助!
相关文章:
JAVA:利用 Content Negotiation 实现多样式响应格式的技术指南
1、简述 Content Negotiation(内容协商) 是 RESTful 服务的重要特性,允许客户端和服务器根据请求的不同特性动态选择适合的响应格式。它是一种在 HTTP 协议中实现的机制,通过它,服务器能够根据客户端需求返回适合的内…...
layui Table单元格编辑支持Enter键换行,包括下拉框单元格
layui Table表格编辑支持Enter键换行 可编辑单元格 $(".layui-table td").keydown(function (e) {// console.log("111",e);var index $(this).index(),tr $(this).parent(tr),isKeydown (event.type "keydown");if (e.code "Enter&q…...
Swoole的MySQL连接池实现
在Swoole中实现MySQL连接池可以提高数据库连接的复用率,减少频繁创建和销毁连接所带来的开销。以下是一个简单的Swoole MySQL连接池的实现示例: 首先,确保你已经安装了Swoole扩展和PDO_MySQL扩展(或mysqli,但在这个示…...
无人机红外热成像:应急消防的“透视眼”
无人机红外热成像:应急消防的“透视眼” 亲爱的小伙伴们,每年一到夏天,应急消防的战士们就像上紧了发条的闹钟,时刻准备应对各种灾害。炎热天气让火灾隐患“蹭蹭”往上涨,南北各地还有防洪救灾、台风、泥石流等灾害轮…...
【redis】Redis操作String类型key的发生了什么?
关于Redis操作(添加、删除、修改、查询)String类型key的完整过程,包括引用源码数据、时序图、磁盘IO读写、数据长度限制和故障处理机制。 数据结构 Redis对象(robj) typedef struct redisObject {unsigned type:4; …...
hdfs之读写流程
写入流程: 客户端Client想将文件a.txt上传至hdfs,首先向Namenode发送请求进行权限校验,Namenode通过后会计算出来三个节点,并将这三个节点告知客户端,客户端将输入进行切割成块,一个一个的块进行传输&…...
研发的立足之本到底是啥?
0 你的问题,我知道! 本文深入T型图“竖线”的立足之本:专业技术 技术赋能业务能力。研发在学习投入精力最多,也误区最多。 某粉丝感发展遇到瓶颈,项目都会做,但觉无提升,想跳槽。于是&#x…...
Baklib揭示内容中台与人工智能技术的创新协同效应
内容概要 在当今信息爆炸的时代,内容的高效生产与分发已成为各行业竞争的关键。内容中台与人工智能技术的结合,为企业提供了一种新颖的解决方案,使得内容创造的流程更加智能化和高效化。 内容中台作为信息流动的核心,能够集中管…...
智慧消防营区一体化安全管控 2024 年度深度剖析与展望
在 2024 年,智慧消防营区一体化安全管控领域取得了令人瞩目的进展,成为保障营区安全稳定运行的关键力量。这一年,行业在政策驱动、技术创新应用、实践成果及合作交流等方面呈现出多元且深刻的发展态势,同时也面临着一系列亟待解决…...
自定义数据集,使用 PyTorch 框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测
在本文中,我们将展示如何使用 NumPy 创建自定义数据集,利用 PyTorch 实现一个简单的逻辑回归模型,并在训练完成后保存该模型,最后加载模型并用它进行预测。 1. 创建自定义数据集 首先,我们使用 NumPy 创建一个简单的…...
UE5 特效
能帮到你的话,就给个赞吧 😘 文章目录 post processexposurebloomvignettesaturationunbound material材质蓝图alt z base colorconstant3Vector roughnessconstant metallicconstant pbrroughnessmetallicmake more realmake some areas rougher than o…...
CMAKE工程编译好后自动把可执行文件传输到远程开发板
# 设置 CMake 最低版本要求 cmake_minimum_required(VERSION 3.10)# 设置项目名称 project(MyProject)# 添加可执行文件,这里以项目名作为可执行文件的名称 add_executable(${PROJECT_NAME} main.cpp)# 设置开发板信息 set(DEVELOPMENT_BOARD_IP "192.168.1.10…...
Windows 程序设计7:文件的创建、打开与关闭
文章目录 前言一、文件的创建与打开CreateFile1. 创建新的空白文件2. 打开已存在文件3. 打开一个文件时,如果文件存在则打开,如果文件不存在则新创建文件4.打开一个文件,如果文件存在则打开文件并清空内容,文件不存在则 新创建文件…...
策略模式 - 策略模式的使用
引言 在软件开发中,设计模式是解决常见问题的经典解决方案。策略模式(Strategy Pattern)是行为型设计模式之一,它允许在运行时选择算法的行为。通过将算法封装在独立的类中,策略模式使得算法可以独立于使用它的客户端…...
具身智能研究报告
参考: (1)GTC大会&Figure:“具身智能”奇点已至 (2)2024中国具身智能创投报告 (3)2024年具身智能产业发展研究报告 (4)具身智能行业深度:发展…...
Windows安装Milvus
安装Milvus 安装Docker前置条件: 安装Mlivus方案一方案二 Attu管理端 安装Docker 系统:Windows 11 家庭中文版 Mlivus:V2.3.0 Attu: V2.3.10 前置条件: 启用“适用于 Linux 的 Windows 子系统”可选功能,才能在 Win…...
Excel分区间统计分析(等步长、不等步长、多维度)
在数据分析过程中,可能会需要统计不同数据区间的人数、某个数据区间的平均值或者进行分组区间统计,本文从excel函数到数据透视表的方法,从简单需求到复杂需求,采用不同的方法进行讲解,尤其是通过数据透视表的强大功能大…...
宝塔mysql数据库容量限制_宝塔数据库mysql-bin.000001占用磁盘空间过大
磁盘空间占用过多,排查后发现网站/www/wwwroot只占用7G,/www/server占用却高达8G,再深入排查发现/www/server/data目录下的mysql-bin.000001和mysql-bin.000002两个日志文件占去了1.5G空间。 百度后学到以下知识,做个记录。 mysql…...
LeetCode 2412.完成所有交易的初始最少钱数:【年度巨献】举例说明(讲明白),由难至简(手脚不乱),附Python一行版
【LetMeFly】2412.完成所有交易的初始最少钱数:【年度巨献】举例说明(讲明白),由难至简(手脚不乱),附Python一行版 文章目录 【LetMeFly】2412.完成所有交易的初始最少钱数:【年度巨献】举例说明(讲明白),由难至简(手脚…...
多人-多agent协同可能会挑战维纳的反馈
在多人-多Agent协同系统中,维纳的经典反馈机制将面临新的挑战,而协同过程中的“算计”(策略性决策与协调)成为实现高效协作的核心。 1、非线性与动态性 维纳的反馈理论(尤其是在控制理论中)通常假设系统的动…...
多模态大模型入门:从CLIP到Qwen-VL,手把手教你搭建第一个视觉语言模型
多模态大模型实战:从CLIP到Qwen-VL的视觉语言探索之旅 当一张图片胜过千言万语时,多模态大模型正在重新定义人机交互的边界。想象一下,上传一张街景照片,AI不仅能识别出咖啡馆招牌上的文字,还能根据店内装修风格推荐适…...
Kubernetes Python Client批量管理秘籍:1000+Pod运维实战
Kubernetes Python Client批量管理秘籍:1000Pod运维实战 【免费下载链接】python Official Python client library for kubernetes 项目地址: https://gitcode.com/gh_mirrors/python1/python Kubernetes Python Client是管理Kubernetes集群的官方Python客户…...
PT-Plugin-Plus:极简高效的PT种子下载辅助工具
PT-Plugin-Plus:极简高效的PT种子下载辅助工具 【免费下载链接】PT-Plugin-Plus PT 助手 Plus,为 Microsoft Edge、Google Chrome、Firefox 浏览器插件(Web Extensions),主要用于辅助下载 PT 站的种子。 项目地址: h…...
LeetCodehot100-25 K 个一组翻转链表
class Solution { public:ListNode* reverseKGroup(ListNode* head, int k) {if (head nullptr || k 1) return head;ListNode dummy(0);dummy.next head;ListNode* prev &dummy; // 指向待反转组的前一个节点while (true) {// 检查剩余节点是否够k个ListNode* tail …...
Vue3 + Cornerstone3D:从零构建支持本地Nifti文件上传与四视图联动的医学影像查看器
1. 为什么选择Vue3Cornerstone3D开发医学影像查看器 医学影像处理一直是前端开发中颇具挑战性的领域,特别是当需要处理专业格式如Nifti时。我在实际项目中尝试过多种技术方案后,发现Vue3和Cornerstone3D的组合特别适合快速构建高性能的医学影像应用。 …...
华为交换机-跨Vlan通信的实战配置指南
1. 华为交换机跨VLAN通信的核心原理 第一次接触跨VLAN通信时,我也被那些专业术语搞得一头雾水。直到把整个流程拆解成生活场景,才真正理解其中的奥妙。想象一下,VLAN就像公司里的不同部门,财务部、技术部、市场部各自在独立的办公…...
PlotJuggler保姆级安装指南:从Ubuntu到Windows,手把手搞定ROS插件与数据可视化
PlotJuggler跨平台安装与配置全攻略:从Ubuntu到Windows的ROS数据可视化实战 在机器人开发和自动驾驶领域,数据可视化是调试和分析的核心环节。PlotJuggler作为一款专业级时间序列数据可视化工具,凭借其强大的数据处理能力和直观的交互界面&am…...
Python AI部署效能革命(Cuvil编译器内核逆向工程实录)
第一章:Python AI部署效能革命的底层驱动力Python 已成为 AI 模型开发的事实标准,但其在生产环境中的部署效能长期受限于解释执行、全局解释器锁(GIL)及内存管理机制。近年来,一场静默却深刻的效能革命正在重塑 Python…...
TypeScript——声明合并
声明合并1、接口声明合并2、枚举声明合并3、类声明合并4、命名空间声明合并4.1、命名空间与命名空间合并4.2、 命名空间与函数合并4.3、 命名空间与类合并4.4、 命名空间与枚举合并5、扩充模块声明6、扩充全局声明声明是编程语言中的基础结构,它描述了一个标识符…...
电子工程开发工具全解析:从EDA到嵌入式系统
电子工程常用开发工具全景解析1. 电子工程软件工具概述电子工程作为信息技术的重要分支,其技术体系涵盖电路设计、信号处理、通信系统等多个专业领域。现代电子工程开发已形成完整的工具链体系,主要包括以下几类:EDA工具:电路设计…...
