目录
基本理论
首先要理解缓存是如何被创建的:
浏览器首先先本地缓存发起创建请求,如果命中则返回数据给浏览器;
如果没有命中,就向代理服务器发起缓存,如果命中代理服务器会发给浏览器以及本地缓存;
如果没命中,则向资源服务器发起创建请求,然后资源服务器再给代理缓存,本地缓存,浏览器数据;
如果要实现这样的功能:
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