深入了解HTTP状态码中的Not Modified

HTTP(超文本传输协议)协议通常使用状态码来表示服务器的响应状态。其中,状态码为304表示 Not Modified,该状态码通常会在浏览器发出请求时被使用。这意味着浏览器已经具有请求的资源的最新版本,因此服务器可以选择不返回内容,而浏览器可以从本地缓存中读取数据,减少了服务器压力并提高了页面加载速度。

一、HTTP缓存机制中的Not Modified

在HTTP缓存机制中,当浏览器要求访问某个资源时,它首先检查缓存中是否存在该资源的拷贝,并检查该资源在缓存中是否仍然有效。如果缓存中的资源是最新的,则浏览器可以直接从缓存中读取该资源,而不会向服务器发送请求。

当浏览器发送条件请求时,服务器将返回状态码304,表示该资源未修改,浏览器可以直接从缓存中读取该资源。

下面是一个使用Python的Flask框架来演示的代码示例:

from flask import Flask, request, make_response

app = Flask(__name__)

@app.route('/image')
def image():
    image_file = open("image.png", "rb").read()
    response = make_response(image_file)
    response.headers.set('Cache-Control', 'public, max-age=3600')
    response.headers.set('Content-Type', 'image/png')
    return response

if __name__ == "__main__":
    app.run()

该代码使用了Flask框架来启动一个简单的HTTP服务器,并向客户端返回一个示例图片。由于请求中包含了Cache-Control头部信息,浏览器将在1个小时内缓存该资源。在下一次请求中,客户端将使用条件请求,并根据服务器的响应决定是否使用缓存来加速页面加载。

二、使用Etag实现Not Modified

Etag是HTTP协议提供的一种机制,用于检测资源的内容是否已经被修改。服务器在返回资源时,可以通过设置Etag头来指定该资源的特征值。浏览器在向服务器发出条件请求时,将Etag头包含在请求中,服务器可以使用该值来判断是否有必要返回资源的内容或返回状态码304。

下面是一个使用Node.js的Express框架来使用Etag实现Not Modified的代码示例:

const express = require('express');
const fs = require('fs');
const app = express();
const PORT = 3000;
const FILE_PATH = './resources/myfile.txt';

app.get('/file', (req, res) => {
  fs.readFile(FILE_PATH, (err, data) => {
    const etag = '"' + generateETag(data) + '"';
    if (req.headers['if-none-match'] === etag) {
      res.status(304).end();
      return;
    }
    res.set({
      'ETag': etag,
      'Content-Type': 'text/plain',
      'Cache-Control': 'public, max-age=3600',
    });
    res.send(data);
  });
});

function generateETag(data) {
  const hash = require('crypto').createHash('md5');
  hash.update(data);
  return hash.digest('hex');
}

app.listen(PORT, () => {
  console.log(`Server listening on port ${PORT}`);
});

该代码使用了Node.js的Express框架来启动HTTP服务器,并根据请求返回一个文本文件的内容。通过使用Crypto模块来计算文件内容的哈希值,并为每个文件资源生成独立的Etag。在接收到条件请求时,服务器使用实体标签来检查资源是否已经过期,从而控制是否返回响应内容。

三、使用Last-Modified实现Not Modified

Last-Modified是HTTP协议另一种可用于检测资源是否已经被修改的机制。服务器在返回资源时,可以通过设置Last-Modified头来指定最新的修改日期和时间。浏览器在向服务器发出条件请求时,将If-Modified-Since头部信息包含在请求中,服务器可以使用该值来决定是否必须返回响应内容或仅返回状态码304。

下面是一个使用Java的Spring框架来使用Last-Modified实现Not Modified的代码示例:

@RestController
public class ApiController {

  @GetMapping(value = "/api")
  public ResponseEntity getResource(
      @RequestHeader(value = "If-Modified-Since", required = false) String modifiedSince) {
    HttpHeaders headers = new HttpHeaders();
    headers.setCacheControl(CacheControl.maxAge(3600, TimeUnit.SECONDS).getHeaderValue());
    Path file = Paths.get("/resources/myfile.txt");
    FileTime lastModified = Files.getLastModifiedTime(file);
    headers.setLastModified(lastModified.toMillis());
    if (modifiedSince != null) {
      ZonedDateTime modifiedSinceTime = ZonedDateTime.parse(modifiedSince).withZoneSameInstant(ZoneId.systemDefault());
      if (Files.getLastModifiedTime(file).toInstant().toEpochMilli() <= modifiedSinceTime.toInstant().toEpochMilli()) {
        return ResponseEntity.status(HttpStatus.NOT_MODIFIED).headers(headers).build();
      }
    }
    String contents = new String(Files.readAllBytes(file), StandardCharsets.UTF_8);
    return ResponseEntity.ok().headers(headers).body(contents);
  }
}

该代码使用Spring框架来启动一个简单的HTTP服务器,并使用Last-Modified标头为资源添加最新修改时间戳。当客户端在随后的请求中发出条件请求时,服务器使用If-Modified-Since标头来确定资源是否已过期,从而仅在必要时返回实际数据,减轻了服务器负载。

总结

Not Modified状态码是HTTP协议中用于表示资源是否已更新的状态码。在HTTP缓存机制中,Not Modified状态码可以有效减轻服务器的负担,提高页面加载速度;在使用Etag或Last-Modified时,服务器可以检测资源的内容是否已经被修改,从而在必要时仅返回状态码而不是实际数据,减少无谓的网络传输。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/244528.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-12 13:02
下一篇 2024-12-12 13:02

相关推荐

  • 为什么要加请求头(HTTP Header)?

    在进行网页抓取(Web Scraping)时,请求头(HTTP Header)扮演着非常重要的角色。请求头中包含了用户代理(User Agent)、cookie、referer等信…

    编程 2025-04-27
  • HTTP请求方式的选择:POST还是GET?

    对于使用xxl-job进行任务调度的开发者,通常需要发送HTTP请求来执行一些任务。但是在发送请求时,我们总是会遇到一个问题:是使用POST还是GET?下面将从多个方面对这个问题进…

    编程 2025-04-27
  • 如何快速发布http接口

    想要快速发布http接口,可以从以下几个方面入手。 一、选择合适的框架 选择合适的框架对于快速发布http接口非常重要。目前比较受欢迎的框架有Flask、Django、Tornad…

    编程 2025-04-27
  • 深入解析Vue3 defineExpose

    Vue 3在开发过程中引入了新的API `defineExpose`。在以前的版本中,我们经常使用 `$attrs` 和` $listeners` 实现父组件与子组件之间的通信,但…

    编程 2025-04-25
  • 深入理解byte转int

    一、字节与比特 在讨论byte转int之前,我们需要了解字节和比特的概念。字节是计算机存储单位的一种,通常表示8个比特(bit),即1字节=8比特。比特是计算机中最小的数据单位,是…

    编程 2025-04-25
  • 深入理解Flutter StreamBuilder

    一、什么是Flutter StreamBuilder? Flutter StreamBuilder是Flutter框架中的一个内置小部件,它可以监测数据流(Stream)中数据的变…

    编程 2025-04-25
  • 深入探讨OpenCV版本

    OpenCV是一个用于计算机视觉应用程序的开源库。它是由英特尔公司创建的,现已由Willow Garage管理。OpenCV旨在提供一个易于使用的计算机视觉和机器学习基础架构,以实…

    编程 2025-04-25
  • 深入了解scala-maven-plugin

    一、简介 Scala-maven-plugin 是一个创造和管理 Scala 项目的maven插件,它可以自动生成基本项目结构、依赖配置、Scala文件等。使用它可以使我们专注于代…

    编程 2025-04-25
  • 深入了解LaTeX的脚注(latexfootnote)

    一、基本介绍 LaTeX作为一种排版软件,具有各种各样的功能,其中脚注(footnote)是一个十分重要的功能之一。在LaTeX中,脚注是用命令latexfootnote来实现的。…

    编程 2025-04-25
  • 深入理解Python字符串r

    一、r字符串的基本概念 r字符串(raw字符串)是指在Python中,以字母r为前缀的字符串。r字符串中的反斜杠(\)不会被转义,而是被当作普通字符处理,这使得r字符串可以非常方便…

    编程 2025-04-25

发表回复

登录后才能评论