前端性能-HTTP缓存

前言

开启 HTTP 缓存是提升前端性能的常见手段之一。通过缓存,浏览器可以临时存储资源,在后续请求中直接使用本地副本,从而有效减少 HTTP 请求次数,显著缩短网页加载时间。以下是 HTTP 缓存的几个关键点:
1、减少重复请求:浏览器存储已请求过的资源,避免重复请求服务器。
2、设置缓存头:通过服务器端的 Cache-Control、Expires 或 ETag 响应头,指导浏览器如何缓存资源。
3、区分静态与动态资源:静态资源(如图片、CSS、JS 文件)可以设置更长的缓存时间,动态资源则需较短的缓存时间或采用验证缓存策略。
4、利用浏览器缓存:配置服务端缓存策略,让浏览器自动处理资源缓存。
5、更新缓存策略:资源更新时,可以通过修改文件名或使用 Last-Modified 和 ETag 验证缓存。
6、监控缓存效果:借助开发者工具监控资源缓存情况,确保缓存策略按预期生效。

NGINX 服务器端配置 HTTP 缓存

与启用 Gzip 压缩类似,HTTP 缓存的开启主要通过 NGINX 服务器的配置完成。本文将以 NGINX 为例,介绍如何高效配置 HTTP 缓存。

配置 Expires 头设置一个长久的 Expires采用高效的缓存政策提供静态资源

  1. cache_expiration.conf
    建议将缓存配置单独存储到文件(如 cache_expiration.conf),并通过 nginx.conf 引入:
    http {
      # 其它配置
      # Specify file cache expiration.
      include web_performance/cache_expiration.conf;
    }
    
    cache_expiration.conf 示例:
    map $sent_http_content_type $expires {
      default                                 1M; # 默认缓存 1 个月
      ''                                      off;# 无内容
      ~*text/css                              1y;# CSS 缓存 1 年
      # Data interchange
      ~*application/atom\+xml                 1h;
      ~*application/rdf\+xml                  1h;
      ~*application/rss\+xml                  1h;
      ~*application/json                      0; # JSON 不缓存
      ~*application/ld\+json                  0;
      ~*application/schema\+json              0;
      ~*application/geo\+json                 0;
      ~*application/xml                       0;
      ~*text/calendar                         0;
      ~*text/xml                              0;
      # Favicon (cannot be renamed!) and cursor images
      ~*image/vnd.microsoft.icon              1w;
      ~*image/x-icon                          1w;
      # HTML
      ~*text/html                             0;
      # JavaScript
      ~*application/javascript                1y;
      ~*application/x-javascript              1y;
      ~*text/javascript                       1y;
      # Manifest files
      ~*application/manifest\+json            1w;
      ~*application/x-web-app-manifest\+json  0;
      ~*text/cache-manifest                   0;
      # Markdown
      ~*text/markdown                         0;
      # Media files
      ~*audio/                                1M;
      ~*image/                                1M;
      ~*video/                                1M;
      # WebAssembly
      ~*application/wasm                      1y;
      # Web fonts
      ~*font/                                 1M;
      ~*application/vnd.ms-fontobject         1M;
      ~*application/x-font-ttf                1M;
      ~*application/x-font-woff               1M;
      ~*application/font-woff                 1M;
      ~*application/font-woff2                1M;
      # Other
      ~*text/x-cross-domain-policy            1w;
    }
    # 时间根据变量 $expires 的配置匹配
    expires $expires;
    
  2. 区分资源类型和缓存时长
    静态资源(CSS、JS、图片等)设置较长的缓存时间。
    动态内容(如 JSON、HTML)设置较短缓存时间或禁用缓存。
    .css、.js 文件缓存 1 年。
    .json 数据不缓存。
    
  3. cache-control.conf
    可通过 cache-control.conf 设置 Cache-Control 头:
    map $sent_http_content_type $cache_control {
        default                           'public, immutable, stale-while-revalidate';
    
        # No content
        ''                                'no-store';
    
        # Manifest files
        ~*application/manifest\+json      'public';
        ~*text/cache-manifest             ''; # `no-cache` (*)
    
        # Assets
        ~*image/svg\+xml                  'public, immutable, stale-while-revalidate';
    
        # Data interchange
        ~*application/(atom|rdf|rss)\+xml 'public, stale-while-revalidate';
    
        # Documents
        ~*text/html                       'private, must-revalidate';
        ~*text/markdown                   'private, must-revalidate';
        ~*text/calendar                   'private, must-revalidate';
    
        # Data
        ~*json                            ''; # `no-cache` (*)
        ~*xml                             ''; # `no-cache` (*)
    }
    
    在 nginx.conf 中引入:
    http {
        # 省略其它配置...
        
        # Add Cache-Control.
        include web_performance/cache-control.conf;
    }
    

HTTP 缓存配置完毕后,在我们请求的静态资源的服务器响应头中就可以看到 Expires 首部字段信息了:
在这里插入图片描述
不怎么变动的资源,尽量给一个长久的 Expires。HTML 页面通常视作动态资源,建议是不设置 Expires 头,否则在指定时间内永远没法取到更新后的 js 和 css 或者其它静态资源。HTML 缓存另一个策略是:不缓存html
如果不希望配置一个全局的静态资源的 Expires 头,可以去掉cache_expiration.conf文件最底部的配置:

# expires $expires

调整后,在 nginx.conf 配置文件中引入的就只是针对不同静态文件过期时间变量 $expires 的配置。这样就不会出现 NGINX 服务器上所有配置的所有 Web 站点都使用相同的 Expires 头的缓存配置,但又都可以访问 $expires 变量了。

HTTP 缓存相关首部字段

  1. Expires 首部字段
    Expires 用来指定资源的过期时间,格式为 HTTP 日期。示例:

    Wed, 23 Jul 2025 12:37:27 GMT
    
    Expires 头要求服务器和客户端的时间要严格同步。如果本地电脑调整了时间,超过了 Exipres 头设置的时间,也会使缓存过期。
    另外,Exipres 头会经常检测过期时间,并且一旦过期了,又需要再服务器中配置提供一个新的日期。所以会有 Exipres 头设置的时间尽量长的策略。
    

    注意:Expires 依赖客户端与服务器时间同步,不够精确,现代项目更推荐使用 Cache-Control。

  2. Cache-Control 首部字段
    Cache-Control 使用 max-age 指令指定组件被缓存多久。它以秒为单位定义更新时间。如果从资源被请求开始过去的秒数小于 max-age,浏览器就会使用缓存版本。它可以消除 Expires 头对于服务器和客户端的时间必须同步的限制。

    	对于不支持 Cache-Control 首部字段的浏览器,我们仍然需要 Expires 头,因此一般都会同时设置 Cache-Control 和 Expires 首部字段。
    	在支持 Cache-Control 头的浏览器,max-age 指定将重写 Expires 头。
    	max-age 指定的设置策略也和 Expires 头一致,尽量设置一个较长的时间。最大可以设置 10 年,一般都设置至少 30 天以上。
    

    注意

     缓存持续时间过长的一个风险就是您的用户不会看到静态文件的更新。若要避免此问题,可以将构建工具配置为在静态资源文件名中嵌入一个哈希,以使每个版本都是唯一的,从而提示浏览器从服务器提取新版本。
    

    Cache-Control 提供更灵活的缓存机制。常见指令包括:
    - public:允许资源被所有用户缓存,包括 CDN。
    - private:资源只能被客户端缓存,不能被代理服务器缓存。
    - no-cache:每次请求都需向服务器验证缓存是否有效。
    - no-store:禁止缓存。
    - immutable:资源不会变化,避免重复验证。
    - max-age=秒数:设置缓存的最大有效期。

    public:表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存。表示相应会被缓存,并且在多用户间共享。默认是 public。
    private:表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它),可以缓存响应内容。响应只作为私有的缓存,不能在用户间共享。如果要求HTTP认证,响应会自动设置为private。
    no-cache:在释放缓存副本之前,强制高速缓存将请求提交给原始服务器进行验证。指定不缓存响应,表明资源不进行缓存。但是设置了no-cache之后并不代表浏览器不缓存,而是在缓存前要向服务器确认资源是否被更改。因此有的时候只设置no-cache防止缓存还是不够保险,还可以加上private指令,将过期时间设为过去的时间。
    only-if-cached:表明客户端只接受已缓存的响应,并且不要向原始服务器检查是否有更新的拷贝.
    no-store:缓存不应存储有关客户端请求或服务器响应的任何内容。表示绝对禁止缓存!
    no-transform:不得对资源进行转换或转变。Content-Encoding, Content-Range, Content-Type 等 HTTP 头不能由代理修改。例如,非透明代理可以对图像格式进行转换,以便节省缓存空间或者减少缓慢链路上的流量。no-transform 指令不允许这样做。
    

    示例:

    location / {
        proxy_pass http://aaa;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
        # 省略其它配置...
    
        # 不缓存 index.html
        expires -1;
        add_header Cache-Control no-store;
    
        # fix history router model in VUE
        try_files $uri $uri/ /index.html;
        error_page 404 /index.html;
    }
    

    在 NGINX 服务器中配置了 Expires 头,在配置反向代理指定了 HTTP1.1 协议后,NGINX 服务器会使用 Cache-Control 头重写 Expires 头,过期时间就是 Expires 头配置的时间。因此如果不是像 HTML 文件这样需要禁止缓存,没有额外的 Cache-Control 头配置。
    在这里插入图片描述
    如果资源变化和新鲜度很重要,但仍想获得缓存的一些速度优势,请使用 no-cache。浏览器仍会缓存设置为 no-cache 的资源,但会先向服务器进行检查,以确保该资源仍为最新资源

  3. Last-Modified 与 ETag

    服务器在检测缓存的资源是否和原始服务器上的资源匹配,使用的是:
    比较最新修改日期(Last-Modified Date)
    比较实体标签(ETag)
    

    客户端会在后续请求中使用 If-Modified-Since 验证缓存是否更新。

    Last-Modified: Tue, 25 Jun 2024 20:20:53 GMT
    

    设置了 Expires 头后,浏览器会缓存资源和它的最新修改日期。再次请求同一资源时,浏览器会使用 If-Modified-Since 头将最新修改日期回传到原始服务器进行比较。如果匹配则返回 304 响应,而不会重新下载组件。

  4. ETag
    ETag:为资源生成唯一标识符,用于缓存校验。示例:

    ETag: "5d8c72a3-3e8"
    

    客户端会在后续请求中使用 If-None-Match 验证。

    它是提供了另一种方式检测缓存的资源是否与原始服务器上的资源是否匹配。
    ETag 的检测机制要比最新修改时间更加灵活。例如,如果实体依据 User-Agent 或者 Accept-Language 头而改变,实体的状态可以反应在 ETag 中。也就是说 ETag 的唯一字符串的值会发生改变。
    ETag 的验证机制是在次访问同一资源的时候,它会使用 If-None-Match 头将 ETag 传回原服务器。如果匹配则返回 304 响应,而不会重新下载资源。
    
  5. ETag 的问题
    通常的 Web 服务器的架构设计都是做了高可用的配置的,是由多台服务器组成的集群构建而成。例如我本地的测试站点的负载均衡的配置:

    upstream cc {
      server 127.0.0.1:8080;
      server 127.0.0.1:8081;
      server 127.0.0.1:8082;
    }
    

    ETag 有个问题,当浏览器分别从两台不同的后端集群服务器中请求同一资源的时候,两台不同的服务器的 ETag 是不会一致的。
    当然,我们可以通过在负载平衡的配置中添加 keepalive 或者设置服务器的 weight 权重,让同一客户端尽量从同一服务器获取资源,但还是无法保证会切换服务器请求资源。

  6. 示例
    以下是一个整合了 Expires 和 Cache-Control 的完整示例:

    	http {
    	  include mime.types;
    	  default_type application/octet-stream;
    	  # 静态资源缓存策略
    	  map $sent_http_content_type $expires {
    	    default 1M;
    	    ~*text/css 1y;
    	    ~*application/javascript 1y;
    	    ~*image/ 1M;
    	    ~*text/html 0;
    	  }
    	  map $sent_http_content_type $cache_control {
    	    default 'public, immutable, max-age=2592000';
    	    ~*text/html 'private, must-revalidate';
    	    ~*application/json 'no-cache';
    	  }
    	  server {
    	    listen 80;
    	    server_name example.com;
    	    location / {
    	      root /var/www/html;
    	      index index.html;
    	
    	      expires $expires;
    	      add_header Cache-Control $cache_control;
    	    }
    	  }
    }
    

注意事项
1. 文件名版本化:静态资源文件更新时,建议在文件名中添加版本号(如 style.v1.css),避免用户加载旧缓存。
2. 开发环境禁用缓存:在开发模式下,可通过浏览器禁用缓存,方便调试。
3. 使用工具检查缓存:可以使用浏览器开发者工具(如 Chrome DevTools)分析缓存行为。

NGINX 配置反向代理缓存

普通的静态资源的 HTTP 缓存外,我们还可以配置反向代理缓存(将服务器集群中的原始资源缓存到代理服务器上),将资源都缓存到 NGINX 服务器所在的代理服务器上。
图片
bypass-cache-purge-nginx.png

如图,用户第一次请求资源,NGINX 服务器会向集群中的服务器请求资源,然后缓存下来。
用户再次请求数据的时候,如果 NGINX 服务器已经缓存了,NGINX 服务器就会直接响应,而不用再向上游的服务器集群的服务器请求资源了。这样就进一步优化了请求的响应速度,也更进一步的优化了前端性能。

  1. 配置反向代理缓存
    要配置反向代理缓存,需要在 NGINX 服务器上配置一个缓存区域,指定缓存路径,目录层级,共享内存的大小等信息。

  2. proxy_cache_path 指令
    proxy_cache_path 是 Nginx 中用于配置反向代理缓存的指令。它定义了缓存存储的位置、缓存大小、缓存的各种参数等。反向代理缓存可以极大地提高性能,减少对后端服务器的负载。
    使用独立的 proxy_cache.conf 文件保存 proxy_cache_path 配置,然后在需要的地方 include 配置;

    proxy_cache_path  ./cache
    levels=1:2
     keys_zone=cache_static:100m  
     inactive=1h  
     max_size=300m  
     use_temp_path=off;
    

    proxy_temp_path=./cache: 缓存临时目录路径;
    levels=1:2: 缓存目录地层级,默认所有缓存文件都放在同一个目录下,从而影响缓存的性能,大部分场景推荐使用2级目录来存储缓存文件;
    keys_zone=cache_static:100m: 在共享内存中设置一块存储区域来存放缓存的 key 和 metadata(类似使用次数),这样 nginx 可以快速判断一个 request 是否命中或者未命中缓存,1m 可以存储 8000 个 key,100m 可以存储 800000 个 key;
    max_size=300m: 最大 cache 空间,如果不指定,会使用掉所有磁盘空间(disk space),当达到配额后,会删除最少使用的 cache 文件;
    inactive=1d: 未被访问文件在缓存中保留时间,本配置中如果 60 分钟未被访问则不论状态是否为 expired,缓存控制程序会删掉文件,默认为10分钟;需要注意的是,inactive 和 expired 配置项的含义是不同的,expired 只是缓存过期,但不会被删除,inactive 是删除指定时间内未被访问的缓存文件;
    use_temp_path=off: 如果为 off,则 nginx 会将缓存文件直接写入指定的 cache 文件中,而不是使用 temp_path 存储,official 建议为 off,避免文件在不同文件系统中不必要的拷贝;

  3. nginx.conf 引用代理缓存配置
    proxy_cache_path 是一个全局性的配置,通常会在 nginx.conf 配置文件中使用 include 方式引入配置:

    http {
      # 省略其它配置...
      
      # 代理缓存配置
      include web_performance/proxy_cache.conf;
    }
    

    这样只要是此 NGINX 服务配置的 Web 站点,就都可以引用 proxy_cache.conf 的代理缓存配置了。

  4. 为 Web 站点的静态资源配置反向代理缓存

    # 上游的服务器负载均衡配置
    include upstreams/www.yao.com.conf;
    	server {
    	    listen [::]:80;
    	    listen 80;
    	    server_name www.cc.com;
    	
    	    # 将 http 请求访问,跳转到相应的 https 访问路径
    	    return 301 https://$host$request_uri;
    	}
    	server {
        # 下次介绍配置 HTTPS 和 HTTP2
        # listen [::]:443 ssl http2;
        listen 443 ssl http2;
    
        server_name www.yao.com;
    
        # 配置证书信息
        include ssl/ssl_engine.conf;
        include ssl/default_certificate_files.conf;
        include ssl/policy_intermediate.conf;
        
        # 针对首页的配置
    	location / {
            proxy_pass http://yao;
            proxy_http_version 1.1;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
            proxy_intercept_errors on;
    
            proxy_next_upstream error timeout invalid_header http_500;
            proxy_connect_timeout 2;
    
            add_header X-Upstream $upstream_addr;
            proxy_pass_header Authorization;
    
            client_body_in_file_only clean;
            client_body_buffer_size 32K;
            client_max_body_size 150M;
    
            # 不缓存 index.html
            expires -1;
            add_header Cache-Control no-store;
    
            # fix history router model in VUE
            try_files $uri $uri/ /index.html;
            error_page 404 /index.html;
        }
        # 访问前端站点的静态文件的代理配置
        # 根据自己的需要添加静态资源的后缀名
        location ~* \.(js|css)$ {
            proxy_pass http://yao;
            
            # 通用的一些反向代理配置
            proxy_http_version  1.1;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
            # 设置资源缓存的 zone,使用之前配置的 cache_static
            proxy_cache cache_static;
            # 设置缓存的 key
            proxy_cache_key $host$uri$is_args$args;
            # 设置状态码为 200 和 304 的响应可以进行缓存,并且缓存时间为 10 分钟
            # 根据自己的站点情况配置时长,时间台长 cache_static 空间很快会消耗完
            proxy_cache_valid 200 304 10m;
             
            # 调整原服务器的缓存配置
            proxy_ignore_headers Expires Set-Cookie Cache-Control;
            proxy_hide_header Cache-Control;
            proxy_hide_header Set-Cookie;
            # 调整原服务器的 Accept-Encoding
            proxy_set_header Accept-Encoding 'gzip';
            
            # 被多次用到的资源才缓存,只用一次的无需代理缓存
            proxy_cache_min_uses 2;
            # 配置自定义头 X-Cache 显示代理缓存命中状态
            add_header X-Cache $upstream_cache_status;
    
            # 根据之前的 $expires 匹配的资源文件类型设置过期时间
            # 当然,你也可以自己根据需要,直接设置一个合适的过期时间
            expires $expires;
            add_header Cache-Control 'public, no-transform';
        }       
    }
    
  5. $upstream_cache_status 变量监测代理缓存状态

    NGINX 提供了$upstream_cache_status这个变量来显示缓存的状态.在这里的配置中添加了一个自定义的 X-Cache 头,使用 $upstream_cache_status 监测代理缓存的状态。以下是 $upstream_cache_status 的可能值:

    MISS - 在缓存中找不到响应,因此从原始服务器获取。然后可以缓存响应;
    BYPASS - 响应是从原始服务器获取的,而不是从缓存中提供的,因为请求与proxy_cache_bypass指令匹配(请参阅下面的“我可以通过我的缓存打孔吗?”)然后可以缓存响应;
    EXPIRED - 缓存中的条目已过期。响应包含来自源服务器的新内容;
    STALE - 内容过时,因为原始服务器未正确响应,并且已配置proxy_cache_use_stale;
    UPDATING- 内容过时,因为当前正在更新条目以响应先前的请求,并且配置了proxy_cache_use_stale更新;
    REVALIDATED - 启用了proxy_cache_revalidate指令,NGINX验证当前缓存的内容仍然有效(If-Modified-Since或If-None-Match);
    HIT - 响应包含直接来自缓存的有效新鲜内容;
    

    默认情况下,NGINX 尊重源服务器的 Cache-Control 头。它不会缓存响应,缓存控制设置为 Private,No-Cache 或 No-Store 或响应头中的 Set-Cookie。NGINX 仅缓存 GET 和 HEAD 客户端请求。

    # 调整原服务器的缓存配置
    proxy_ignore_headers Expires Set-Cookie Cache-Control;
    proxy_hide_header Cache-Control;
    proxy_hide_header Set-Cookie;
    

    这段配置就是为了启用代理缓存,用以忽略源服务器的 Cache-Control 头。
    另外,还特别添加了NGINX 服务器自己的 Cache-Control 头的配置:

    add_header Cache-Control 'public, no-transform';
    

    表示允许响应被被缓存,并且在多用户间共享。不得对资源进行转换或转变。
    图片
屏幕截图 2024-07-28 093746.png

    再看看 X-Cache 头,也就是 $upstream_cache_status 的值已经是 HIT 状态,表示该静态资源已经被代理缓存命中了。反向代理缓存存储如下:
    图片
proxy-cache-content.png
    从截图我们可以看到,配置的2级缓存已经启用了。缓存的文件是二进制的内容,截取一段用文本编辑器打开的数据为:
    在这里插入图片描述
    这里的KEY:

    KEY: www.yao.com/js/909.86428264.js
    

    正是我们配置的反向代理缓存的中 proxy_cache_key 配置的数据格式:

    # 设置缓存的 key
    proxy_cache_key $host$uri$is_args$args;
    
    
  6. proxy_cache_purge 清除反向代理缓存
    若要手动清除缓存,可以使用 proxy_cache_purge 模块。配置代码如下:

    # 用于清除缓存,假设一个URL为: https://www.yao.com/#/default
    # 访问 https://www.cc.com/#/purge/defaut 就可清除该URL的缓存
    location ~ /purge(/.*) {
        # 设置只允许指定的IP或IP段才可以清除URL缓存。
        allow 127.0.0.1;
        deny all;
        proxy_cache_purge cache_static $host$uri$is_args$args;
    }
    

    这个清理缓存的路径应该只有特定(运维)人员有权限访问,清理缓存。

  7. 编译安装 Nginx 并且添加 ngx_cache_purge 模块

    另外,proxy_cache_purge 不是 NGINX 服务器自带的指令模块,需要手动下载编译安装。
    第1步:获取 nginx
    在 /etc/nginx/source 下执行,具体是在那个目录,可以自行决定:

    wget http://nginx.org/download/nginx-1.21.0.tar.gz
    tar -zxvf nginx-1.12.2.tar.gz
    

    第2步:获取 ngx_cache_purge
    在 /etc/nginx/source 下执行,具体是在那个目录,可以自行决定,这里建议与下载的 nginx 目录一致:

    	wget https://github.com/FRiCKLE/ngx_cache_purge/archive/2.3.tar.gz
    tar -zxvf 2.3.tar.gz
    

    第3步:修改 nginx 安装配置

    ./configure --prefix=/etc/nginx  \
    --with-http_stub_status_module  \
    --with-http_ssl_module --with-stream  \
    --with-http_gzip_static_module  \
    --with-http_sub_module \
    --with-pcre  \
    --add-module=../ngx_cache_purge
    

    –add-module=…/ngx_cache_purge 这是新增的,如果要查看以前的 configure 参数,可以使用以下命令查看,然后复制后再后边加入需要添加的配置即可。

    nginx -V
    

    第4步:编译安装
    如果以前未安装过:

    	make && make install
    

    编译安装完成后,配置 nginx。
    如果以前已经安装了 nginx 服务器,需要先停止 nginx 服务:

    # 默认 nginx 已经配置为系统服务
    service nginx stop
    

    重新编译,在 /etc/nginx/source 下执行

    	make
    

    将编译好的 nginx 文件覆盖到/etc/nginx/sbin/nginx:

    cp objs/nginx /etc/nginx/sbin/nginx
    

    安装编译完成,然后按前文到需要的模块配置 proxy_cache_purge, 然后检测配置文件是否正确:

    nginx -t/T
    

    如果配置检测通过,就可以重启 nginx 服务:

    service nginx start
    

    另外,NGINX 服务器的商业版 Nginx Plus 中自带了清理缓存的指令,有兴趣的同学可以自己查阅一下相关资料。

开启 HTTP 缓存后的性能对比

  1. 未开启 HTTP 缓存
    在这里插入图片描述

    完成时间:1.79秒
    DOMContentLoaded:442毫秒
    加载时间:1.72秒

  2. 开启 HTTP 缓存

    图片
cache.png

    完成时间:677毫秒
    DOMContentLoaded:190毫秒
    加载时间:625秒

效果还是很明显的,特别是像我测试站点这种 SPA 页面,一切都要等 js 资源加载完成了才绘制界面,加载速度至关重要!资源加载的越快,意味着用户看到 UI 界面就越快,用户体验也就越好。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/954582.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Unity-Game4Automation PRO 插件】

Game4Automation PRO 插件 是一个用于 Unity 引擎 的工业自动化仿真工具,它提供了对工业自动化领域的仿真和虚拟调试支持,特别是在与工业机器人、生产线、PLC 系统的集成方面。该插件旨在将工业自动化的实时仿真与游戏开发的高质量 3D 可视化能力结合起来…

【Linux】--- 进程的等待与替换

进程的等待与替换 一、进程等待1、进程等待的必要性2、获取子进程status3、进程等待的方法(1)wait()函数(2)waitpid函数 4、多进程创建以及等待的代码模型5、非阻塞接口 轮询 二、进程替换1、替换原理2、替…

一个超快低延迟.Net网络通信库:支持TCP, SSL, UDP, HTTP,HTTPS, WebSocket多协议

今天给大家推荐一个性能好、低延迟.Net网络通信库,基本支持所有协议。 01 项目简介 NetCoreServer是一个基于.NET Core的开源项目,一个高性能、跨平台的异步套接字服务器与客户端库。该项目支持多种传输协议,包括TCP、SSL、UDP、HTTP、HTTP…

苍穹外卖08——(涉及接收日期格式数据、ApachePOI导出报表、sql获取top10菜品数据)

营业额统计 service层 在需要处理空值、与数据库交互或使用集合时,Integer 、Double是更好的选择。 // 导入string工具类 import org.apache.commons.lang.StringUtils; Service // 标记该类为Spring的服务组件 Slf4j // 引入日志功能 public class Repor…

数据结构9——二叉搜索树

🥇1.二叉搜索树的概念 二叉搜索树(Binary Search Tree,BST)又称二叉排序树或二叉查找树,其要么是一棵空树,要么具有以下性质: ①:左子树上所有节点的值都小于根节点; ②:右子树上所有节点的值都…

如何使用wireshark 解密TLS-SSL报文

目录 前言 原理 操作 前言 现在网站都是https 或者 很多站点都支持 http2。这些站点为了保证数据的安全都通过TLS/SSL 加密过,用wireshark 并不能很好的去解析报文,我们就需要用wireshark去解密这些报文。我主要讲解下mac 在 chrome 怎么配置的&…

c++ haru生成pdf输出文本实例

haru是一个开源的生成pdf的库,花时间终于编译成功,以下是一个特别简单的写文本的实例: #include "hpdf.h" void CDemoDlg::OnBnClickedOk() { HPDF_Error_Handler error_handler NULL; HPDF_Doc pdf; pdf HPDF_New(…

Redis与MySQL主从复制原理解析

目录 1. 介绍2. Mysql主从复制的工作原理3. Mysql复制的类型3.1 基于语句的复制(Statement-based Replication, SBR)3.2 基于行的复制(Row-based Replication, RBR)3.3 混合复制(Mixed Replication) 4. Red…

一步到位Python Django部署,浅谈Python Django框架

Django是一个使用Python开发的Web应用程序框架,它遵循MVC(Model-View-Controller)设计模式,旨在帮助开发人员更快、更轻松地构建和维护高质量的Web应用程序。Django提供了强大的基础设施和工具,以便于处理复杂的业务逻…

迅为RK3568开发板篇OpenHarmony配置HDF驱动控制LED-新增 topeet子系统-编写 bundle.json文件

bundle.json 文件内容如下所示: 下面是对各个字段的解释: 1. name: "ohos/demos" - 这是组件或项目的名称,这里表示它属于 OHOS(OpenHarmony OS)生态系统下的一个名为"demos"的组件。 2. descri…

STM32 物联网智能家居 (三) 输入子系统

STM32 物联网智能家居 (三) 输入子系统 下面是物联网智能家居的输入子系统,见下图,在输入子系统中会实现按键输入、网络输入、标准输入Scanf,其中的网络输入放入到网络子系统中进行讲解。 一、输入子系统核心功能 STM32 物联网智能家居输入…

Windows 正确配置android adb调试的方法

下载适用于 Windows 的 SDK Platform-Tools https://developer.android.google.cn/tools/releases/platform-tools?hlzh-cn 设置系统变量,路径为platform-tools文件夹的绝对路径 点击Path添加环境变量 %adb%打开终端输入adb shell 这就成功了!

【C#深度学习之路】如何使用C#实现Yolo8/11 Segment 全尺寸模型的训练和推理

【C#深度学习之路】如何使用C#实现Yolo8/11 Segment 全尺寸模型的训练和推理 项目背景项目实现推理过程训练过程 项目展望写在最后项目下载链接 本文为原创文章,若需要转载,请注明出处。 原文地址:https://blog.csdn.net/qq_30270773/article…

线性回归超详解

目录 一、回归问题 vs 分类问题 二、线性回归 1、一句话理解 2、数学推导 2.1 线性函数表示 2.2 损失函数 2.3 梯度下降 2.3.1 什么是梯度 2.3.2 梯度下降目标 2.3.3 过程 2.3.4 迭代公式 3、特征预处理 3.1 为什么要预处理 3.2 数据归一化方法 1)最小…

docker 部署 Kafka 单机和集群

一、准备工作 安装 Docker 确保本机已安装 Docker。可以通过以下命令检查 Docker 是否已安装:docker --version如果未安装,可以访问 Docker 官网下载并安装 Docker Desktop(Windows 和 Mac)或使用包管理器安装(Linux&…

Uniapp开发安卓App,配置第一次打开软件出现的弹窗-隐私政策提示框

这里是直接使用的uniapp官方所提供的“原生隐私政策提示框”,废话不多说,直接上教程! 1.manifest.json—>安卓/IOS启动界面配置—>勾选“使用原生隐私政策提示框”2.勾选后,在你的项目下就会出现一个文件,andro…

微信小程序:播放音频

在小程序开发中,音频播放是一个重要的功能。本文将详细介绍小程序音频播放的相关知识点,帮助开发者更好地掌握小程序音频播放的实现方法。 一、小程序音频播放的基本流程 在小程序中,音频播放的基本流程如下: 获取音频数据&#…

Unity解决滑动条的value值的滑动条消失问题

在这里我们看到原本的value的滑动条消失了 解决办法 把编辑器的边框往外面拉一下就可以了(之前遇到这个问题还重启了几次unity没想到居然是这个问题)

Mac上安装Label Studio

在Mac上安装Anaconda并随后安装Label Studio,可以按照以下步骤进行: 1. 在Mac上安装Anaconda 首先,你需要从Anaconda的官方网站下载适用于Mac的安装程序。访问Anaconda官网,点击“Download Anaconda”按钮,选择适合M…

微软震撼发布:Phi-4语言模型登陆Hugging Face

近日,微软公司在Hugging Face平台上正式发布了其最新的语言模型Phi-4,这一发布标志着人工智能技术的又一重要进步。Phi-4模型以其140亿参数的高效配置,在复杂推理任务中表现出色,特别是在数学领域,更是展现出了卓越的能…