HTTP之Last-Modified、Etage、If-Modified-Since理论与实践(C++ Qt实现)

本文深入解析HTTP缓存机制,包括缓存的创建流程,如何利用Last-Modified与Etag进行资源验证,以及no-cache和no-store响应头的作用。通过一个Qt实现的服务器示例,展示如何在实际应用中控制缓存行为。

目录

 

 

基本理论

博主例子


 

基本理论

首先要理解缓存是如何被创建的:

浏览器首先先本地缓存发起创建请求,如果命中则返回数据给浏览器;

如果没有命中,就向代理服务器发起缓存,如果命中代理服务器会发给浏览器以及本地缓存;

如果没命中,则向资源服务器发起创建请求,然后资源服务器再给代理缓存,本地缓存,浏览器数据;

 

如果要实现这样的功能:

1. 浏览器本地有缓存,但每次还要向服务器发起请求,看看资源是不是更新了;

2. 如果更新了服务器发送新资源给浏览器,如果没更新就叫浏览器读取缓存;

 

要使用HTTP实现上面的功能,要具备以下的知识点:

1.  服务器响应头中的no-cahce为每次发起请求都要在服务器那边验证下,如果服务器能让浏览器使用本地缓存,才能使用。no-store为本地和代理服务器都不能存储缓存;每次都要拿新的。

2. 服务器响应头中有两根验证头,一个是Last-Modified和一个Etag。

3. Last-Modified为上次修改时间,配合请求头中的If-Modified或If-Unmodified-Since使用,对比上传修改时间以验证资源是否需要更新。

4. Etag为数字签名,配合If-Match或If-Non-Match使用,对比资源的签名判断是否使用缓存。

 

博主例子

服务器运行截图如下:

这个是回正常的200的HTTP数据包;

这样是回304读取本地缓存的包,

先把他调到正常会HTTP包;

浏览器数据如下:

这里看看其大小:

当变为回304时:

发现大小改变了:

但文本内容还是没变:

看看数据包详细信息:‘

程序结构如下:

源码如下:

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
class QTcpServer;
class QTcpSocket;
QT_END_NAMESPACE

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();

protected slots:
    void newConnectionSlot80();
    void errorStringSlot80();
    void sendMsg80();
    void btnClicked();

private:
    Ui::Widget *ui;
    QTcpServer *m_tcpServer80;
    QTcpSocket *m_tcpSocket80;

};

#endif // WIDGET_H

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QTcpServer>
#include <QDebug>
#include <QTcpSocket>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    m_tcpServer80 = new QTcpServer(this);
    m_tcpServer80->listen(QHostAddress::Any, 80);
    connect(m_tcpServer80, SIGNAL(newConnection()), this, SLOT(newConnectionSlot80()));
    connect(m_tcpServer80, SIGNAL(acceptError(QAbstractSocket::SocketError)), this, SLOT(errorStringSlot80()));
    connect(ui->pushButton, SIGNAL(clicked(bool)), this, SLOT(btnClicked()));
}

Widget::~Widget()
{
    delete ui;
    m_tcpServer80->close();
}

void Widget::newConnectionSlot80()
{
    qDebug() << "newConnectionSlot80() called";
    m_tcpSocket80 = m_tcpServer80->nextPendingConnection();
    sendMsg80();
    //connect(m_tcpSocket80, SIGNAL(readyRead()), this, SLOT(sendMsg80()));
    //connect(m_tcpSocket80, SIGNAL(connected()), this, SLOT(sendMsg80()));
}

void Widget::errorStringSlot80()
{
    qDebug() << m_tcpServer80->errorString();
}

void Widget::sendMsg80()
{
    QString contentStr;
    QString str;
    if(ui->pushButton->text() == "正常回HTTP包"){

        contentStr = "<html>"
                     "<head>"
                     "<title>"
                     "Socket 80"
                     "</title>"
                     "</head>"
                     "<body>"
                     "<h1>Socket 80</h1>"
                     "</body>"
                     "</html>";

        //send msg
        str = "HTTP/1.1 200 OK\r\n";
        str.append("Server:nginx\r\n");
        str.append("Content-Type:text/html\r\n");
        str.append("Access-Control-Allow-Origin: *\r\n");
        str.append("Connection:keep-alive\r\n");
        str.append("Cache-Control: max-age=200000\r\n");
        str.append("Last-Modified: 777777\r\n");
        str.append("Etage: 888888\r\n");
        str.append(QString("Content-Length:%1\r\n\r\n").arg(contentStr.size()));
        str.append(contentStr);
        //qDebug() << str;
    }
    else{

        str = "HTTP/1.1 304 OK\r\n";
        str.append("Server:nginx\r\n");
        str.append("Content-Type:text/html\r\n");
        str.append("Access-Control-Allow-Origin: *\r\n");
        str.append("Connection:keep-alive\r\n");
        str.append("Cache-Control: max-age=200000, no-cache\r\n");
        str.append("Last-Modified: 777777\r\n");
        str.append("Etage: 888888\r\n");
        str.append(QString("Content-Length:%1\r\n\r\n").arg(contentStr.size()));
    }

    m_tcpSocket80->write(str.toStdString().c_str());
}

void Widget::btnClicked()
{
    if(ui->pushButton->text() == "正常回HTTP包"){

        ui->pushButton->setText("回304包");
    }
    else{

        ui->pushButton->setText("正常回HTTP包");
    }
}

 

源码打包下载地址:

https://github.com/fengfanchen/Qt/tree/master/HTTPLast-Modified

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT1995

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值