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 协议中实现的机制,通过它,服务器能够根据客户端需求返回适合的内…...
Python 函数魔法书:基础、范例、避坑、测验与项目实战
Python 函数魔法书:基础、范例、避坑、测验与项目实战 内容简介 本系列文章是为 Python3 学习者精心设计的一套全面、实用的学习指南,旨在帮助读者从基础入门到项目实战,全面提升编程能力。文章结构由 5 个版块组成,内容层层递进…...
OpenBMC:编译
1.安装依赖 OpenBMC是基于Yocto搭建的,基于不同的OS预先需要安装的依赖包和工具,清参考: 1 System Requirements — The Yocto Project 5.1.999 documentation 2.下载代码 OpenBMC的源码位于: openbmc/openbmc: OpenBMC Distri…...
Effective Objective-C 2.0 读书笔记—— objc_msgSend
Effective Objective-C 2.0 读书笔记—— objc_msgSend 文章目录 Effective Objective-C 2.0 读书笔记—— objc_msgSend引入——静态绑定和动态绑定OC之中动态绑定的实现方法签名方法列表 其他方法objc_msgSend_stretobjc_msgSend_fpretobjc_msgSendSuper 尾调用优化总结参考文…...
使用EVE-NG-锐捷实现OSPF
一、OSPF基础知识 Open shortest Path First(OSPF)开放式最短路径优先协议 1.OSPF的关系状态 (1)邻居关系(TWO-WAY) 只发送hello包不发送LSA包(链路状态通告包) (2)邻接关系(FULL) OSPF设备与设备之间相互建立OSPF关系,初始为邻居关系(TWO-WAY)状态࿰…...
电商系统-用户认证(三)基于公钥解析JWT令牌
一、 基于私钥生成jwt令牌 步骤: 导入认证服务 将shangcheng_user_auth工程导入到项目中去,如下图 启动eureka,再启动认证服务 3) 认证服务中创建测试类 public class CreateJwtTest { /**** 创建令牌测试*/Testpublic voi…...
【论文投稿-第八届智能制造与自动化学术会议(IMA 2025)】HTML, CSS, JavaScript:三者的联系与区别
大会官网:www.icamima.org 目录 前言 一、HTML(超文本标记语言):网页的骨架 HTML 的作用: 例子: 总结: 二、CSS(层叠样式表):网页的外观设计 CSS 的…...
Baklib赋能下的内容中台智能化推荐系统解析与展望
内容概要 在数字化时代,内容中台的智能化推荐系统正逐渐成为各类企业提升用户体验与运营效率的重要工具。该系统通过集成和分析大量用户数据及内容信息,能够实现精准的个性化推荐,为用户提供最相关的内容。 以下是内容中台智能化推荐系统的…...
2024年记 | 凛冬将至
放弃幻想,准备斗争! 考研or就业? 上大学以来,考研上名校在我的心里一直是一颗种子,2024年初,当时的想法是考研和就业两手抓。买了张宇的高数现代,想要死磕! 也记了挺多笔记... 如果…...
虚幻基础08:组件接口
能帮到你的话,就给个赞吧 😘 文章目录 作用 作用 组件接口:可以直接调用对方的组件接口,而无需转换为actor。 实现对象间的通知。 A 通知 B 做什么。...
http3网站的设置(AI不会配,得人工配)
堡塔PHP项目中配置nginx1.26.0设置http3协议 # 文件所在服务器中的路径 /www/server/nginx/conf/nginx.confuser www www; worker_processes auto; error_log /www/wwwlogs/nginx_error.log crit; pid /www/server/nginx/logs/nginx.pid; worker_rlimit_nofile 512…...
数据分析系列--②RapidMiner导入数据和存储过程
一、下载数据 点击下载AssociationAnalysisData.xlsx数据集 二、导入数据 1. 在本地计算机中创建3个文件夹 2. 从本地选择.csv或.xlsx 三、界面说明 四、存储过程 将刚刚新建的过程存储到本地 Congratulations, you are done....
使用iis服务器模拟本地资源服务器unityaddressables热更新出错记录
editor中设置了using exculexing 模拟远程加载addressable可以实现资源热更新,build后的软件却没有成功。 iis服务器中mime中需要设置bundle的文件扩展名,时editor成功,build后失败 原因没有设置hash的扩展名,设置后editor和buil…...
Ubuntu x64下交叉编译ffmpeg、sdl2到目标架构为aarch64架构的系统(生成ffmpeg、ffprobe、ffplay)
一、编译SDL2-2.0.9 (1), ./configure --prefix/home/z/Desktop/sdl2 --enable-sharedyes --enable-nasmno --enable-audiono --enable-ossno --enable-alsano --enable-alsa-sharedno --enable-pulseaudiono --enable-pulseaudio-sharedno …...
进程通讯——类型和发展
进程常用交互方法如上...
深度学习:从基础到前沿
🔥个人主页🔥:孤寂大仙V 🌈收录专栏🌈:Linux 🌹往期回顾🌹:【Linux】进程地址空间与虚拟地址空间 🔖流水不争,争的是滔滔不 一、深度学习的基础知…...
Node.js与MySQL模块结合:打造安全高效的用户信息管理系统
摘要 本文探讨使用Node.js构建前端项目并导入MySQL模块创建数据库连接对象的方法。文中讲解了共享数据库连接对象,定义SQL语句查询和更新用户信息(排除密码字段以保护隐私),以及根据用户ID更新基本信息、重置密码和更新头像的具体…...
【项目】基于Qt开发的音乐播放软件
目录 项目介绍 项目概述 界面开发 界面分析 创建工程 主界面布局设计 窗口主框架设计 界面美化 主窗口设定 添加图片资源 head处理 播放控制区处理 自定义控件 BtForm 推荐页面 自定义CommonPage 自定义ListItemBox 自定义MusicSlider 自定义VolumeTool 音…...
C语言,无法正常释放char*的空间
问题描述 #include <stdio.h> #include <stdio.h>const int STRSIZR 10;int main() {char *str (char *)malloc(STRSIZR*sizeof(char));str "string";printf("%s\n", str);free(str); } 乍一看,这块代码没有什么问题。直接书写…...
Promise.race
Promise.race 是 JavaScript 中 Promise 对象的一个静态方法,用于将多个 Promise 实例包装成一个新的 Promise 实例。这个新的 Promise 实例会在 最先完成(无论是 fulfilled 还是 rejected) 的 Promise 完成时完成,并返回该 Promi…...
@RestControllerAdvice 的作用
系列博客目录 文章目录 系列博客目录1.ControllerAdvice 有什么用主要功能 2.与 RestControllerAdvice 的区别3.苍穹外卖中的使用4.RestControllerAdvice可以指定范围吗(1)指定应用到某些包中的 RestController(2)指定应用到具有特…...
信息学奥赛一本通 1390:食物链【NOI2001】| 洛谷 P2024 [NOI2001] 食物链
【题目链接】 ybt 1390:食物链【NOI2001】 洛谷 P2024 [NOI2001] 食物链 【题目考点】 1. 种类并查集 2. 带权并查集 【解题思路】 解法1:种类并查集 已知有三类动物A、B、C。A吃B,B吃C,C吃A。 对于B类动物来说,…...
MATLAB中fetchOutputs函数用法
目录 语法 说明 示例 在后台运行函数 fetchOutputs函数的功能是从在后台运行的函数中检索结果。 语法 [Y1,...,Ym] fetchOutputs(F) [Y1,...,Ym] fetchOutputs(F,UniformOutputfalse) 说明 [Y1, ..., Ym] fetchOutputs(F) 从 Future 数组 F 中检索出 m 个结果。 F 中…...
数据可视化的图表
1.折线图反映了一段时间内事物连续的动态变化规律,适用于描述一个变量随另一个变量变化的趋势,通常用于绘制连续数据,适合数据点较多的情况。 2.散点图是以直角坐标系中各点的密集程度和变化趋势来表示两种现象间的相关关系,常用于显示和比较数值。当要在不考虑时间…...
简易CPU设计入门:控制总线的剩余信号(四)
项目代码下载 请大家首先准备好本项目所用的源代码。如果已经下载了,那就不用重复下载了。如果还没有下载,那么,请大家点击下方链接,来了解下载本项目的CPU源代码的方法。 CSDN文章:下载本项目代码 上述链接为本项目…...
基础IO(2)
基础IO(2) 理解“⼀切皆⽂件” ⾸先,在windows中是⽂件的东西,它们在linux中也是⽂件;其次⼀些在windows中不是⽂件的东西,⽐如进程、磁盘、显⽰器、键盘这样硬件设备也被抽象成了⽂件,你可以使…...
Java数据库操作指南:快速上手JDBC【学术会议-2025年数字化教育与信息技术(DEIT 2025】
大会官网:www.ic-deit.org 前言 在现代企业应用中,数据库是数据存储和管理的重要组成部分。Java作为一种广泛使用的编程语言,提供了多种方式与数据库进行交互。本文将介绍 JDBC(Java Database Connectivity)&#x…...
IDM-VTON本地部署教程:双重编码 + 文字提示,解锁真实野外试穿
一、介绍 IDM-VTON:改进扩散模型,实现真实的野外虚拟试穿。 技术原理:改进扩散模型,利用视觉编码器提取服装高级语义信息并与交叉注意力层融合,通过并行 UNet 结构的 GarmentNet 捕捉服装低级特征并与自注意力层结合&…...
编译安装PaddleClas@openKylin(失败,安装好后报错缺scikit-learn)
编译安装 前置需求: 手工安装swig和faiss-cpu pip install swig pip install faiss-cpu 小技巧,pip编译安装的时候,可以加上--jobs64来多核编译。 注意先升级pip版本:pip install pip -U pip3 install faiss-cpu --config-s…...
【2024年华为OD机试】 (C卷,200分)- 矩阵匹配(JavaScriptJava PythonC/C++)
一、问题描述 问题描述 给定一个大小为 ( N \times M )(( N \leq M ))的矩阵,从中选出 ( N ) 个数,要求任意两个数字不能在同一行或同一列。求选出来的 ( N ) 个数中第 ( K ) 大的数字的最小值。 输入描述 输入矩阵要求&#…...
