dongqin8652 2017-02-09 13:23
浏览 122

Web服务器缓存问题

Everything started when I was trying to improve the loading times of thumbnail pictures in a gallery of sort i have. the paths of all images come from a JSON file/string/response along with several details about them, in order to build the UI.

My first thought was to cache them with JavaScript itself:

for( let i = 0; i < data.length; i++ ) {

    let thumbnail = new Image();
    thumbnail.src = data[ i ].thumbnail;
}

ES2015 with BabelJS being used

I know it's not the best approach as I should load them on demand (i.e. when accessing their offsets in JSON) or even asynchronously with AJAX. In fact I did try both ways too, but I didn't manage to make the other data wait for the image to be fully loaded before fill the UI.

But this is a matter for later ^_^

So, I checked the Chrome Inspector and under Network tab all JPG were being loaded as expected but when actually using the images, modifying the src attribute of the container designed for the preview (see below), every image was being loaded again.

$( 'figure img' ).attr( 'src', data[ current ].thumbnail );

This is just a fragment. 'current' is the gallery counter to navigate through the JSON

After exhausting my testing skills I ended up believing the issue was my server.

I'm currently using PHP Internal Webserver for development because, at least until now, I didn't have the need of a complete server solution. It's bad to have several command-line windows opened, but anyway...

For the record, the webserver is started like this:

php.exe -c "path\to\php.ini" -S "0.0.0.0:8080" -t "." "routing.php"

Running under Windows environment >.<

My previous routing file was very blunt, just returning false if requesting an image, js, css, font... so, after reading several topics in here, I changed it trying to include some caching:

<?php

if( preg_match( '/\.(js|ico|gif|jpg|png|css|eot|svg|ttf|woff|php)$/', $_SERVER["REQUEST_URI"] ) ) {

    date_default_timezone_set( 'America/Sao_Paulo' );

    $file = sprintf( '.%s', $_SERVER['REQUEST_URI'] );

    if( ! file_exists( $file ) ) {
        header( 'HTTP/1.1 404 Not Found' );
    }

    $eTag = md5_file( $file );

    if( $eTag !== FALSE ) {
        header( 'Etag: ' . $eTag );
    }

    header( 'Cache-Control: public, max-age=2592000' );

    $mTime = filemtime( $file );

    if( $mTime !== FALSE ) {

        $GMD = gmdate('D, d M Y H:i:s', $mTime );

        header( sprintf( 'Last-Modified: %s GMT', $GMD ) );

        if( isset( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ) {

            $mSince = strtotime( $_SERVER['HTTP_IF_MODIFIED_SINCE'] );

            if( $mSince !== FALSE && $mSince == $GMD ) {

                header( 'HTTP/1.1 304 Not Modified' ); return false;
            }
        }

        if( isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ) {

            $noneMatch = str_replace( '"', '', stripslashes( $_SERVER['HTTP_IF_NONE_MATCH'] ) );

            if( $noneMatch == md5( $file . $mTime ) ) {
                header( 'HTTP/1.1 304 Not Modified' ); return false;
            }

            if( $noneMatch == $eTag ) {
                header( 'HTTP/1.1 304 Not Modified' ); return false;
            }
        }
    }

    // Resource not cached yet

    header( 'Content-Type: '   . mime_content_type( $file ) );
    header( 'Content-Length: ' . filesize( $file ) );

    return false;
}

include __DIR__ . '/index.php';

The performance was considerably better but, testing with one single file, directly, the first load took ~300ms, the second ~5ms, the third ~300ms, the fourth ~5ms and so on. o.O

Then I tested it in the whole Application and the caching problem persisted, although, theoretically, the images were already loaded with JavaScript and stored in the Image Object, they were loaded once again when their respective offset in the JSON was accessed through the navigation.

Also, when refreshing the page multiple times I didn't have the same "jumping" response times as with direct access. everything not coming from CDNs (jQuery, Bootstrap...) were being loaded again, again and again. >:(

After more research, two of the culprits I've found were the Cache-control not being set and the overall status code.

I couldn't find a way to send the 304 Header using the PHP Internal WebServer, not because I don't know how, afterall the code is the same, but because all implementations I've seen depends on some $_SERVER entries that, as far as I know, are provided by Apache (and maybe other dedicated server applications).

Also, for some reason, in Chrome Inspector, opening the Headers section of a resource, I don't see in there the Cache-control directive under Response Headers even though I did set it, as you can see, with ~30 days of expiration.

More than how could I solve these issue I would like to understand why is this happening.

  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥50 永磁型步进电机PID算法
    • ¥15 sqlite 附加(attach database)加密数据库时,返回26是什么原因呢?
    • ¥88 找成都本地经验丰富懂小程序开发的技术大咖
    • ¥15 如何处理复杂数据表格的除法运算
    • ¥15 如何用stc8h1k08的片子做485数据透传的功能?(关键词-串口)
    • ¥15 有兄弟姐妹会用word插图功能制作类似citespace的图片吗?
    • ¥200 uniapp长期运行卡死问题解决
    • ¥15 latex怎么处理论文引理引用参考文献
    • ¥15 请教:如何用postman调用本地虚拟机区块链接上的合约?
    • ¥15 为什么使用javacv转封装rtsp为rtmp时出现如下问题:[h264 @ 000000004faf7500]no frame?