HTTP 协议请求头 If-Match、If-None-Match 和 ETag

2023-11-03 07:36
文章标签 协议 http 请求 none match etag

本文主要是介绍HTTP 协议请求头 If-Match、If-None-Match 和 ETag,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

概述

在 HTTP 协议中,请求头 If-MatchIf-None-MatchIf-Modified-SinceIf-Unmodified-SinceIf-Range 主要是为了解决浏览器缓存数据而定义的请求头标准,按照协议规范正确的判断和使用这几个请求头,可以更精准的处理浏览器缓存,从而达到提高系统性能和减少系统带宽的占用的目的。

更精准的处理 Web 缓存效果是可以很明显的:

  • 1、 减少了网络交互,加快页面响应速度,增强用户体验;
  • 2、 减少了网络带宽消耗,因为没有更新的资源就不需要重复返回了,特别是图片、视频、下载文件这类大响应体请求;

当请求中存在上述 If-xxx 时,服务器对附加的条件进行判断,当判定条件为真,才会执行标准的数据处理和数据返回,否则直接返回对应的HTTP错误码。

针对服务端原始资源是否变更目前有两类处理规则:基于修改时间的(If-Modified-SinceIf-Unmodified-Since)和基于自定义标识的(If-MatchIf-None-Match),还有一个是处理文件断电续传使用到的 If-Range

经常做服务端开发的会发现,基于时间的并不能很精准的进行缓存判断,有些场景下后端资源可能在1秒钟以内进行了变更,时间请求头只精确到秒,是不足以覆盖这种场景的。还有一些场景是我们没有定义修改时间的,可能是基于其他标志记录是否被修改的。这种情况下,我们使用 If-MatchIf-None-Match 来进行资源是否变更的更精准判断,这两个头基于一个自定义字符串传送,这个字符串你可以自己定义,例如用 md5,时间戳都可以,需要注意它俩需要结合 ETag 请求头一起使用(ETag 指代一个独一无二的版本号字符串,称为“实体标签”)。

下文针对 If-Match、If-None-Match 和 ETag 的交互原理及使用方法进行说明。

详解

服务端对资源记录一个 ETag(实体标记)的字段,当资源更新后ETag也会随之更新。
所以当客户端 If-Match 的值若与服务端的ETag一致,才会执行请求,否则拒绝处理返回412状态码。

交互图:

在这里插入图片描述
在这里插入图片描述

示例代码:

package com.example.webfluxreactivedemo1.controller;import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** HTTP请求头IfMatch和ETag处理** @author 单红宇* @date 2023/11/2 10:09*/@RestController
@RequestMapping
public class IfMatchController {/*** 获取资源接口** @param id         资源ID* @param clientETag 请求头中的 If-None-Match* @return ResponseEntity*/@GetMapping("/resource/{id}")public ResponseEntity<String> getResource(@PathVariable String id,@RequestHeader("If-None-Match") String clientETag) {// 检查资源是否存在以及资源最新的ETag是否与请求头中的If-None-Match匹配boolean resourceExists = checkResourceExists(id);boolean etagMatch = checkETagMatch(id, clientETag);if (!resourceExists) {// 如果资源不存在,返回404 Not Foundreturn ResponseEntity.status(HttpStatus.NOT_FOUND).build();} else if (!etagMatch) {// 如果资源存在且ETag不匹配(即资源已经发生了变更),则返回资源内容return ResponseEntity.ok().header(HttpHeaders.ETAG, this.generateETag(id)).body("Resource content");} else {// 如果资源存在且ETag匹配(即资源没有发生变更),返回304和空响应体return ResponseEntity.status(HttpStatus.NOT_MODIFIED).build();}}/*** 修改文章内容** @param id          文章ID* @param clientETag 请求头中的 If-Match* @return ResponseEntity*/@GetMapping("/updateArticle/{id}")public ResponseEntity<String> updateArticle(@PathVariable String id,@RequestHeader("If-Match") String clientETag) {// 检查资源是否存在以及资源最新的ETag是否与请求头中的If-Match匹配boolean etagMatch = checkETagMatch(id, clientETag);if (etagMatch) {// 如果资源存在且ETag匹配,即文章没有被其他人修改过,执行更新操作String newETag = "返回文章最新的ETag";// articleService.update(id);return ResponseEntity.ok().header(HttpHeaders.ETAG, newETag).body("修改成功");} else {// 如果ETag不匹配,说明文章被其他人修改过,用户需要获取最新内容后再基于最新内容修改提交,防止多人同时修改文章内容出现覆盖问题// 返回412 Precondition Failedreturn ResponseEntity.status(HttpStatus.PRECONDITION_FAILED).build();}}// 如果资源存在但ETag不匹配,返回412 Precondition Failed/*** 检查资源是否存在** @param id 资源ID* @return true=存在*/private boolean checkResourceExists(String id) {// 在这里实现检查资源是否存在的逻辑return true;}/*** 检查资源ETag是否匹配,即判定资源的ETag是否发生了变动** @param id         资源ID* @param clientETag 浏览器客户端传过来的ETag* @return 当资源已经被更新时返回false,资源未更新返回true*/private boolean checkETagMatch(String id, String clientETag) {// 在这里实现检查资源ETag是否与请求头中的If-Match/If-None-Match匹配的逻辑return true;}/*** 生成一个ETag** @param resourceId 资源ID* @return ETag*/public String generateETag(String resourceId) {// 在这里实现检查资源是否存在的逻辑String eTag = "根据resourceId按照自己的逻辑生成etag,比如你可以使用md5";// 注意ETag必须使用双引号包起来返回,这是HTTP协议规范要求return "\"" + eTag + "\"";}
}

常见误区

以下是关于这两个字段的一些常见误区:

  • 错误的使用方式:有些开发者可能会错误地将If-None-Match和If-Match混淆或颠倒使用。例如,本应使用If-None-Match来检查缓存有效性的情况下使用了If-Match,这可能导致不必要的请求失败。

  • 不了解Etag的工作机制:Etag是一个与特定资源关联的确定值,通常由服务器生成并存储。当资源发生变化时,Etag也会相应地更新。而有些开发者可能误认为Etag是由客户端生成和管理的,这可能导致无法正确使用If-Match或If-None-Match。

  • 不正确的Etag格式:Etag的格式应该是ASCII字符串,可能包含一个"W/"前缀来表示弱比较算法。有些开发者可能会忽略这一点,导致Etag格式不正确,从而影响缓存控制的效果。

为了避免这些错误,建议开发者仔细阅读HTTP规范,确保正确理解和使用If-Match和If-None-Match字段。同时,也需要了解和掌握Etag的工作机制和正确的使用方法。


(END)

这篇关于HTTP 协议请求头 If-Match、If-None-Match 和 ETag的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/336612

相关文章

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

详解Java如何向http/https接口发出请求

《详解Java如何向http/https接口发出请求》这篇文章主要为大家详细介绍了Java如何实现向http/https接口发出请求,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用Java发送web请求所用到的包都在java.net下,在具体使用时可以用如下代码,你可以把它封装成一

C#使用HttpClient进行Post请求出现超时问题的解决及优化

《C#使用HttpClient进行Post请求出现超时问题的解决及优化》最近我的控制台程序发现有时候总是出现请求超时等问题,通常好几分钟最多只有3-4个请求,在使用apipost发现并发10个5分钟也... 目录优化结论单例HttpClient连接池耗尽和并发并发异步最终优化后优化结论我直接上优化结论吧,

Java后端接口中提取请求头中的Cookie和Token的方法

《Java后端接口中提取请求头中的Cookie和Token的方法》在现代Web开发中,HTTP请求头(Header)是客户端与服务器之间传递信息的重要方式之一,本文将详细介绍如何在Java后端(以Sp... 目录引言1. 背景1.1 什么是 HTTP 请求头?1.2 为什么需要提取请求头?2. 使用 Spr

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一

Python如何实现 HTTP echo 服务器

《Python如何实现HTTPecho服务器》本文介绍了如何使用Python实现一个简单的HTTPecho服务器,该服务器支持GET和POST请求,并返回JSON格式的响应,GET请求返回请求路... 一个用来做测试的简单的 HTTP echo 服务器。from http.server import HT

Java如何接收并解析HL7协议数据

《Java如何接收并解析HL7协议数据》文章主要介绍了HL7协议及其在医疗行业中的应用,详细描述了如何配置环境、接收和解析数据,以及与前端进行交互的实现方法,文章还分享了使用7Edit工具进行调试的经... 目录一、前言二、正文1、环境配置2、数据接收:HL7Monitor3、数据解析:HL7Busines

SpringBoot中Get请求和POST请求接收参数示例详解

《SpringBoot中Get请求和POST请求接收参数示例详解》文章详细介绍了SpringBoot中Get请求和POST请求的参数接收方式,包括方法形参接收参数、实体类接收参数、HttpServle... 目录1、Get请求1.1 方法形参接收参数 这种方式一般适用参数比较少的情况,并且前后端参数名称必须

BUUCTF靶场[web][极客大挑战 2019]Http、[HCTF 2018]admin

目录   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 [web][HCTF 2018]admin 考点:弱密码字典爆破 四种方法:   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 访问环境 老规矩,我们先查看源代码