深入了解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/zh-tw/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

發表回復

登錄後才能評論