PHP关于 header 头 Etag、Last-Modified、Expires 配合使浏览器缓存生效

假设我们要利用后端读取音频资源并输出到浏览器(可能做防盗链用)

    public function get_music(){
        ......

        $file_source = 'xxxx';  //音频文件的资源地址

        //检查文件是否存在
        if (! file_exists ($file_source)) {
            header('HTTP/1.1 404 NOT FOUND');
        } else {
            //获取文件Etag相同则返回304并结束运行本接口,使客户端读取缓存,否则附加Etag值返回客户端浏览器进行记录
            $Etag = md5_file($file_source); //获取文件md5,其实文件md5可用作Etag作为记录,校检文件是否改变。
            if(array_key_exists('HTTP_IF_NONE_MATCH', $_SERVER) and $_SERVER['HTTP_IF_NONE_MATCH'] == $Etag){
                header("HTTP/1.1 304 Not Modified");  //返回304
                exit();  //结束运行
            } else {
                header("Etag:" . $Etag);  //标记Etag
            }

            //以只读和二进制模式打开文件
            $file = fopen ( $file_source, "rb" );
            //文件大小
            $file_size = filesize($file_source);
            //请求范围的度量单位
            header("Accept-Ranges: bytes" );
            //文件名
            header("Content-Disposition: filename=" . $file_name );
            //缓存控制
            header("Cache-Control: public, max-age=31536000");
            //返回资源类型
            header("Content-Type: audio/mpeg");
            //文件真实大小
            header('Content-Length: ' . $file_size);
            //上次修改时间
            header('Last-Modified: '.gmdate('D, d M Y H:i:s',time())." GMT");
            //到期时间
            header('Expires: '.gmdate('D, d M Y H:i:s', time() + 3600*24*60)." GMT");
            //启用缓存
            header("Pragma: Pragma");

            //读取文件内容并直接输出到浏览器
            echo fread ( $file, filesize ( $file_source ) );
            fclose ($file);
            //exit(0);    //如果你在TP5框架中使用导致Content-Type无法更改,请加上此处让header生效
        }
    }