簡體   English   中英

如何讓瀏覽器或 PHP 緩存一個 fetch() 請求?

[英]How to let the browser or PHP cache a fetch() request?

這與fetch() 基本相反,如何發出非緩存請求? .

假設我們有客戶端:

<div onclick="fetch('/data.php').then(r => r.text()).then(s => console.log(s));">Click me</div>

PHP 中的服務器端:

<?php echo "hello"; /* in reality, this can be much more data 
                       and/or updated later with other content */ ?>

Click me多次單擊時,請求通過網絡多次完成,請求響應代碼為“200”。

因此,瀏覽器/PHP沒有進行緩存

在此處輸入圖像描述

如果此處實際上不需要此數據,如何防止該數據被多次傳輸?

潛在的解決方案:由於/data.php可以在服務器上更新,服務器可以使用日期時間元數據timestamp服務數據請求,我可以將其存儲在客戶端JS變量timestamp中。 然后在對/data.php進行下一個fetch請求之前,我可以做一個初步請求

fetch('/get_last_modification_date.php').(r => r.json()).then(data => {
    if (data['timestamp'] != timestamp)
        fetch('/data.php')...       // if and only if new data is here
});

因此,我們只執行一次fetch('/data.php')...如果該數據的時間戳比我們已有的時間戳更新。

這會起作用,但似乎我們正在手動做一些可以通過瀏覽器+PHP緩存機制完成的事情。

如何要求 PHP 和瀏覽器為我們做所有這些緩存?

一種簡單的方法是將調用包裝到fetch

理想情況下,這將在 class 或閉包中,但為了簡潔起見,現在是全局變量。

var fetched = false;
function clickMe(someURL) {
    if (fetched) { return; }
    fetched = true;
    fetch(someURL).then() // etc.
}

// onclick="clickMe('/data.php')"

我看到了兩種解決方案; 而且我已經在我的應用程序中實現了兩者,所以它們都可以工作。

解決方案A :在使用 fetch API 時指定緩存值, 而不是只傳遞要從中獲取給定資源/發布特定數據/任何內容的鏈接 根據您的需要從defaultno-storereloadno-cacheforce-cacheonly-if-cached中進行選擇,如第一個鏈接中所述。

將此與您提到的timestamp相結合,以相應地確定緩存是否仍然fresh / stale等(如第一個鏈接中所述),您對 go 很好。

解決方案B :我已經在某些情況下實現了這一點,例如,允許對同一端點進行多種GET請求,而一些請求(如GET https://example.org/api/v1/users )使后續那些進一步縮小的(如GET https://example.org/api/v1/users/employees/4 ),已過時。

在這樣的場景B中,我啟動了一個 JS object,如下所示:

const users = {};

假設我然后例如通過GET https://example.org/api/v1/users獲取用戶,並且該請求還在employees鍵下檢索此 API 的員工(無論出於何種原因)。 我用檢索到的數據填充users ,因此也使用employees密鑰,例如持有 5 名員工。

然后,在后續請求中,例如GET https://example.org/api/v1/users/employees/4 例如,在這種情況下,我檢查users object 是否已經通過執行以下操作檢索了employees

if (.users.hasOwnProperty('employees')) { // Only fetch your data in this case }

僅當我的本地 js 環境中不存在數據時才向服務器發出請求。 然后,您可以根據需要為您的users object 添加一個timestamp屬性,如果后續請求的時間戳低於該timestamp ,則檢查上述條件,例如,請求應從本地變量中檢索,而不是從服務器中檢索。 這種模仿你的緩存,原理是一樣的。

當然,解決方案B真的取決於您如何設置服務器響應等,所以我會說解決方案A是標准方法。

有關解決方案A 的更多信息,您可能還想快速閱讀HTTP 請求的緩存何時仍被認為是新鮮的? ,或者更確切地說只是快速檢查整個 HTTP 緩存文檔

您可能還想看看這個問題,因為第一個答案顯示了一個如何顯式設置Cache-Control Header 的示例。 在這個意義上; 您應該考慮設置為您的timestampCache-Control header 的max-age鍵的值。 這就是瀏覽器通常本機處理緩存的方式。

fetch()的行為與常規的 HTTP 請求相同,因此您只需應用有關緩存的標准 HTTP 規則即可。 例如,您可以使用我將解釋的If-Modified-Since機制。

當服務器返回資源的以下標頭時:

Cache-Control: no-cache
Last-Modified: <date in RFC2616 format>

然后,在后續請求中,瀏覽器將發送帶有Last-Modified日期的If-Modified-Since header。 如果服務器返回304 (未修改)狀態,則瀏覽器將使用資源的緩存版本。

備注:盡管它的名字, no-cache指令並不意味着資源不能被緩存; 它只是意味着瀏覽器在使用它之前必須通過服務器對其進行驗證。

為了說明這一點,我假設您要發送一些data.txt文件的內容:

<?php
// Get the modification time of the resource
$dataTime = filemtime('data.txt');

if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']))
{
    $sinceTime = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
    if($sinceTime==$dataTime)
    {
        // The browser already has the latest version of the resource
        header('HTTP/1.1 304 Not Modified');
        exit;
    }
}

// Send the resource
header('Cache-Control: no-cache');
header('Last-Modified: '.gmdate('D, d M Y H:i:s T', $dataTime));
header('Content-Type: text/plain; charset=UTF-8');
readfile('data.txt');
?>

使用+ Date.now()處理獨特的請求; 並且不要在這樣的實驗中使用 static 文本,在 output 中使用動態內容:

我做了我自己的實驗(在 xampp windows 中)基於你的問題(在 Firefox 中)查看控制台,然后在服務器的標題部分..

索引.php

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="Generator" content="Custa">
<title></title>
</head>
<body>
<div onclick="fetch('data.php?'+ Date.now()).then(r => r.text()).then(s => console.log(s));">Click me</div>
</body>
</html>

數據.php

<?php

echo microtime(true);

?>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM