目录
拔出萝卜带出泥
- 在我的网站支持WebP啦中,提及我的图片接口可以按特定格式返回图片,在webp兼容性上处理又可以回退到jpg。
- 在图片的尺寸和布局偏移中分析了图片尺寸的好处,以及我的图片链接是带尺寸信息的。
- 在浏览器中图片延迟加载,我延迟加载进行了学习和记录,一技对兼容的思考
- 在在mavon-edit中实现图片lazyloading中,我们在前端实现了原生的延迟加载和Sarfari兼容性处理。不支持loading使用lozad
- 在图片传输和压缩以及渲染形式分别又在为什么图片传输不开启gzip压缩呢?、图片渐进式初探中进行了学习和测试
- 在[摘录]彻底弄懂浏览器缓存策略中,学习了浏览器的缓存策略
- 在服务器上也研究了[转载]Nginx+PHP Xsendfile文件传输和caddy反向代理缓存(reverse proxy cache),后者是对CDN的试探性测试
- 在理论的补充上,也学习了浏览器的渲染逻辑和部分性能优化,还有对png格式的简单了解。主要体现在[摘]浏览器的回流和重绘、[摘]png的压缩和过滤和[阅读笔记]网络基础-渲染性能
- 最后是通过图片加载策略对页面性能影响测试页面进行测试,得到一个图片加载策略对页面性能影响中好像没什么乱用的结果。
而那最初最初的原因,就是我发现挂了个代理后访问我的网站,发现有一丢丢慢。
正文
这篇文字主要是记录后端思路和一些代码
上传图片和图片尺寸
这里做的改进就是在上传图片时,处理对图片进行大小检查等处理完,增加的时对图片尺寸信息的读取,保存并返回给前端。也就是图片链接中extr字段。
这么做的好处时,在后台的图片选择或者在文字编辑插入图片时,返回的图片链接接就是包含图片尺寸信息的。
图库管理和从图库选择
在后台的图库中,显示的图片都是原比例的100*100的缩略图,也就是图片的尺寸和布局偏移 - 图片尺寸设定方法中的第二个例子。固定的盒子尺寸和图片尺寸可以减少页面的回流和避免布局偏移,缩略图可以加载显示。并且公用一个组件。
存储和输出图片
存储和缓存
目前的策略只永久缓存原图,对于小尺寸缩略图和其他个格式的图片,都以文件缓存处理,当然文件缓存的时间还是比较长的。这样的好处时,在迁移或者备份的时候,可以不管缓存目录,对于冷门图片,也可以被定时清除释放空间。缺点是,可能会有点慢和一些缓存机制的相关问题。当然这里或多或少有一点为后续自己的CDN服务器提前做一点点的试探。
输出图片
文件检查
每个图片链接会有一个文件id,用于图片的查找和健全,对于非法id,直接拒绝请求。
304响应
对于设定了 Tag 或者 Last-Modified的请求进行文件检查并做304或404响应
文件命中或生成
- 如果是原图,返回原图路径
- 如果是多格式,以请求头accept内容进行兼容性处理
- 如果是缓存图片,检查缓存是否有效,返回文件路径
- 缓存无效时,按指定规则生成图片,返回文件路径
这里使用 文件id+图片类型+尺寸 做缓存键名。这里还夹带了私货,jpg和png生成的是渐进式图片。
设定缓存头
- 设定 Cache-Control 和Expire,直接浏览器缓存
- 设定Last-Modified 与 ETag,在浏览器缓存失效启用304
发送文件
- 在未开启x-sendfile时,由php输出,此时缓存由php返回的缓存头控制。
- 开启x-sendfile时,由nginx 输出,此时缓存头可以由nginx 进行管理。
php图片输出部分代码
$dst_func = function($dst){
return 'upload'.DS.substr($dst, strlen(XPATH_UPLOAD));
};
header('Last-Modified: ' . gmdate("D, d M Y H:i:s", $file['ctime'])." GMT" );
header('Cache-Control: max-age=604800' );
header('Expires: '.gmdate("D, d M Y H:i:s", time()+604800)." GMT" );
header('Cache-Control: public');
header('Pragma: public');
$type_arr = ['jpg'=>'image/jpeg','png'=>'image/png','bmp'=>'image/bmp','webp'=>'image/webp'];
if(in_array($type,['image/jpeg','image/png','image/bmp'])){
if(!empty($ret['f'])){
$f = 'jpg';
if(count($ret['f'])>1){
$filter = XFilter::S()->Regxp('/(.*?webp.*)/');
if(!$filter->check($_SERVER['HTTP_ACCEPT'])){
array_pop($ret['f']);
}
}
$f = array_pop($ret['f']);
}else{
$f = array_search($type,$type_arr);
}
$_type = $type_arr[$f];
if(!empty($ret['w'])
|| !empty($ret['h'])
|| ($type != $_type)){
$_dst = ImageMod::thumbnail($ret['idm'],$ret['w'],$ret['h'],$dst,$f);
if(!$_dst){
return;
}
$file['file_size'] = filesize($_dst);
$dst_func = function($dst){
return 'runtime'.DS.'thumbnail'.substr($dst, strlen(XPATH_RUNTIME.'thumbnail'));
};
$dst = $_dst;
$type = $_type;
}
}
header('Content-Type: ' . $type);
header('Content-Length: ' . $file['file_size']);
if (defined('USE_X_SEND_FILE') && USE_X_SEND_FILE) {
$dst = $dst_func($dst);
if (stripos($_SERVER['SERVER_SOFTWARE'], 'nginx') !== false) {
header('X-Accel-Redirect: ' . '/send_file/'.$dst);
} else {
header('X-Sendfile: '.'/send_file/'.$dst);
}
} else {
header('ETag: "'.$ret['idm'].'"');
readfile($dst);
}
缩略图部分
这里用的是 php图片处理Imagine常用例子,更详细用法可以到官网的文档中查看。
其他思考
- 图片加水印
暂时不需要,不过解析一波csdn.net的图片链接又给了我一波思路。