网络基础 - HTTP 缓存

博客分类: 江河计划

网络基础 - HTTP 缓存

算法

选择排序

var arr = [4,2,3,2,3,5,1,0,7,6]
Array.prototype.selectSort = function(){
    for(var i=0; i<this.length; i++){
        var min = i;
        for(var j=i+1; j<this.length; j++){
            if(this[j] < this[min]){
                min = j
            }
        }
        if(this[i] !== this[min]){
            var swap = this[i];
            this[i] = this[min];
            this[min] = swap
        }
    }
}

插入排序

var arr = [4,2,3,2,3,5,1,0,7,6]
Array.prototype.insertSort = function(){
    for(var i=1; i<this.length; i++){
        var j = i,
            temp = this[i];
        while(j > 0 && this[j - 1] > temp){
            this[j] = this[j - 1];
            j--;
        }
        this[j] = temp;
    }
}

正则

首尾空格:/^\s*|\s*$/g

URL:/[a-zA-Z]+:\/\/[^\s]*/

身份证:/(^\d{15}$)|(^\d{18}$)|(^\d{17}[\d|X|x]$)/

国内座机:/((^\d{3})-(\d{8})$)|(^(\d{4})-(\d{7})$)/

整理知识 HTTP 缓存

当浏览器首次对一个资源发起请求时,在不考虑其他参数的情况下,请求完成之后会将当次请求的结果缓存下来,以便下次请求更快响应。过程如下

首次发起资源请求:

image

浏览器再次对同一资源发起请求:

image

详解第一次发起请求流程:

image

强制缓存,此时资源只要未过期,都会触发缓存,直接对内容进行返回,如果缓存失效,则立即发起新的请求对服务器进行请求,然后将结果放入缓存中。

image

对比缓存:首先获取资源的标识,发送请求到服务器验证资源标志是否失效,如果未失效,则浏览器从本地获取资源,如果失效,再发起真是请求到服务器,请求新的资源内容。

image

强制缓存

强制缓存的关键在于如何判断缓存数据是否失效,判断的信息在 response header 信息中,主要由(Expires/Cache-control)来标明。

Expires

Expires的值为服务端返回的到期时间,即下一次请求时,请求时间小于服务端返回的到期时间,直接使用缓存数据。不过Expires 是HTTP 1.0的东西,现在默认浏览器均默认使用HTTP 1.1,所以它的作用基本忽略。

另一个问题是,到期时间是由服务端生成的,但是客户端时间可能跟服务端时间有误差,这就会导致缓存命中的误差。所以HTTP 1.1 的版本,使用Cache-Control替代。

Cache-control

Cache-Control:是最重要的规则。常见的取值有private、public、no-cache、max-age,no-store,默认为private。

对比缓存

对比缓存,顾名思义,需要进行比较判断是否可以使用缓存。 浏览器第一次请求数据时,服务器会将缓存标识与数据一起返回给客户端,客户端将二者备份至缓存数据库中。再次请求数据时,客户端将备份的缓存标识发送给服务器,服务器根据缓存标识进行判断,判断成功后,返回304状态码,通知客户端比较成功,可以使用缓存数据。

对于对比缓存来说,缓存标识的传递是我们着重需要理解的,它在请求header和响应header间进行传递,一共分为两种标识传递,接下来,我们分开介绍

Last-Modified / If-Modified-Since

Etag / If-None-Match

优先级高于 Last-Modified / If-Modified-Since

用户行为与缓存

用户操作 Expires/Cache-Control Last-Modified/Etag
地址栏回车 有效 有效
页面链接跳转 有效 有效
新开窗口 有效 有效
前进、后退 有效 有效
F5刷新 无效(BR重置max-age=0) 有效
ctrl + F5刷新 无效(重置CC=no-cache) 无效(请求头丢弃该选项)

小程序打包自动替换环境

小程序开发过程中需要对应不同的测试环境,发布线上的时候总是手动替换环境,容易忘记替换环境,如果测试环节有疏忽就容易导致线上小程序连接的是测试环境,已经有过故障是关于这方面。总结起来又三方面问题:

  1. 上线环境切换手动容易忘记
  2. 没有自动化 merge_master 的流程,容易丢失代码
  3. 上线之后代码没有自动 merge 到 master,导致下次提交代码丢失

对应三方面的问题目前是想将发布环境自动化,思路是首先 check 有没有 merge master,如果没有则报错,然后将配置替换成线上配置,压缩打包,生成 ratg,并将代码 merge 到 master。下面是流程脚本的实现。

const fs = require('fs');
const path = require('path');
const childProcess = require('child_process');
const spawn = childProcess.spawn;

const envReg = new RegExp(/const\s*env\s*=\s*[\'|\"].*[\'|\"]/);
const configPath = path.resolve(__dirname, 'src/config/index.js');
var configInfo = fs.readFileSync(configPath).toString();
const checkMergePath = path.resolve(__dirname, 'check_merge.sh');
const createTagPath = path.resolve(__dirname, 'create_tag.sh');
const branch = process.argv.pop();

var env = configInfo.match(envReg)[0];
var configRes = configInfo.replace(/const\s*env\s*=\s*'.*'/, "const env = 'wechat'");
fs.writeFileSync(configPath, configRes);

const checkMaster = () => {
    const checkMasterSpawn = spawn(checkMergePath, [branch]);
    checkMasterSpawn.stdout.on('data', (data) => {
        console.log(data.toString());
    });
    checkMasterSpawn.on('close', (code) => {
        if (code == 0) {
            console.log('check master 成功');
            pack();
        }
    });
}

const pack = () => {
    const packSpawn = spawn('cross-env', ['NODE_ENV=production', 'wepy', 'build', '--no-cache']);
    packSpawn.stdout.on('data', (data) => {
        console.log(data.toString());
    });
    packSpawn.stderr.on('data', (data) => {
        console.log(data.toString());
    });
    packSpawn.on('close', (code) => {
        if (code == 0) {
            console.log('打包成功');
            createTag();
        } else {
            console.log(code)
        }
    });
}

const createTag = () => {
    const createTagSpawn = spawn(createTagPath, ['rtag', 'online', 'true']);
    createTagSpawn.stdout.on('data', (data) => {
        console.log(data.toString());
    });
    createTagSpawn.on('close', (code) => {
        if (code == 0) {
            console.log('create tag 成功')
            var configRes = configInfo.replace(/const\s*env\s*=\s*'.*'/, env);
            fs.writeFileSync(configPath, configRes);
            console.log('发布完成')
        }
    });
}

checkMaster();

check_merge.sh

#!/bin/sh
#检查主干上的提交是否都已合并到分支
function check_error()
{
 if [ $? != "0"  ];then
 echo  "$1"
 echo "$2"
 exit 1
 fi
}

function get_branch()
{
 git symbolic-ref HEAD 2>&1 | sed -e 's,.*/\(.*\),\1,' | grep -v "not a symbolic"

}

function get_tag()
{
 git describe 2>&1 | grep -v " tags"

}

if [ $# != 1  ];then
echo "wrong param! sh check_merge.sh branch|tag"
exit 1;
fi

echo "branch为$1"
work_dir=`pwd`
git config remote.origin.url
check_error "非git目录" "请检查$work_dir"
echo "[check_merge]now is at"
git log  | head -3

if [ "x$1" == "xtag"  ];then
 tag=` get_tag `
else
 tag=`get_branch`
fi

msg="目录信息`git status`"
[ "x$tag" != "x"  ]
check_error "检索分支出错,模式为$1" "$msg"

msg=`git log origin/master ^${tag} --oneline`
[ "x$msg" == "x"  ]
check_error "代码需要merge,分支为$tag,以下的commit没有提交" "$msg"

echo "分支$tag merge检查通过"

create_tag.sh

#!/bin/sh
#生成tag push远端
#函数声明####################################################################################
function check_error()
{
 if [ $? != 0  ];then
 echo "$1"
 exit 1
 fi
}

function check_exit()
{
        if [ $? == 0  ];then
        echo "$1"
        exit 0
        fi
}

function get_branch()
{
        git symbolic-ref HEAD 2>&1 | sed -e 's,.*/\(.*\),\1,' | grep -v "not a symbolic"

}

function get_tag()
{
        git describe 2>&1 | grep -v " tags"

}
################################################################################################

work_dir=`pwd`
git config remote.origin.url
check_error "非git目录" "请检查$work_dir"

if [ $# != 3  ];then
echo "wrong param! sh create_tag.sh btag|rtag msg mergeOrNot"
exit 1;
fi

# echo "$1" | grep -P "rtag|btag" >/dev/null 2>&1
# check_error "请输入rtag或btag"


tag=$1"-"`date "+%Y%m%d-%H%M%S"`

msg=$2

need_merge=$3

echo "[merge]now is at"
git log  | head -3
current=` get_tag `


[[ "x"$current =~ "xratg"   ]]
check_exit "当前commit,无需再打tag"
#[ "x"$current == "x"  ] && [[ "x$1" =~ "xrtag"  ]]
#check_exit "只有beta能打rtag"
#[ "x"`get_branch` != "x"  ] && [[ "x$1" =~ "xrtag"  ]]
#check_exit "分支不能打rtag"
[ "x"`get_branch` == "x"  ] && [[ "x"$current =~ "xbtag"  ]] && [[ "x$1" =~ "xbtag"  ]]
check_exit "当前commit无需打新btag"


echo "[merge2]now is at"
git log  | head -3
git tag -a $tag -m "$msg"
check_error "生成tag失败,tag为$1"

git reset --hard $tag
echo "[merge3]now is at"
git log  | head -3

git rev-parse HEAD
echo "[merge4]now is at"
git log  | head -3

git push origin $tag
check_error "push tag到远端失败,mod为$1,tag为$tag"

if [ "$need_merge" ==  "true"  ] ;then
 #git push origin ${tag}^{}:master
 git checkout master
 git fetch origin
 git merge origin/master
 git reset --hard
 git merge $tag
 git push origin master
 check_error "merge tag $branch 到master失败"
 echo “代码已merge主干”
fi