使用Node.js开发一个简单的图片服务器

欢迎访问我的个人网站:https://coderyuan.com

背景

之前在开发实验室官网(https://www.xiyoumobile.com)的时候,由于图片特别多,学校服务器走电信和教育网,带宽也不够,在某些网络环境图片加载十分缓慢,而且有时候主页打开需要10s+的时间,所以考虑从图片压缩上节省网络带宽

目前业界的图片压缩方案有以下几种,他们的压缩比都很高,都可以有效减小图片文件的体积

方案 提出者 编码类型 开源 官网 浏览器支持情况
WebP Google VP8 https://developers.google.com/speed/webp/ Chrome、Opera、Edge、Android,及其他基于Chromium内核的浏览器
BPG Fabrice Bellard HEVC http://bellard.org/bpg
TPG 腾讯 AVS2(类似AVC) 未知 QQ浏览器
JPEG XR 微软 未知 (微软已投奔WebP) IE、Edge

根据TPG推出时腾讯的微信公众号文章来看,TPG的压缩算法相比WebP而言,能够使体积变得更小,图片更清晰,但是适用范围还是太局限了,所以还是选择了WebP

但主要问题是前端代码中已经固定了某些静态图片资源的URL及扩展名,数据库中保存的HTML中的图片引用也是如此,即使把图片全部转换为WebP格式,如何保证不改动HTML及CSS代码,就能够对支持的浏览器返回WebP格式图片,而不支持的浏览器返回JPG/PNG?

于是经过一段时间摸索和整理,就有了现在用在我个人网站的coderyuan-image-server:https://github.com/yuanguozheng/coderyuan-image-server

基本原理及流程

判断浏览器是否支持WebP

首先引用一段来自w3的定义(RFC 2616):https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

The Accept request-header field can be used to specify certain media types which are acceptable for the response. Accept headers can be used to indicate that the request is specifically limited to a small set of desired types, as in the case of a request for an in-line image.

   Accept         = "Accept" ":"
                    #( media-range [ accept-params ] )
   media-range    = ( "*/*"
                    | ( type "/" "*" )
                    | ( type "/" subtype )
                    ) *( ";" parameter )
   accept-params  = ";" "q" "=" qvalue *( accept-extension )
   accept-extension = ";" token [ "=" ( token | quoted-string ) ]

这里定义了HTTP请求头中Accept字段的含义——表示Response可以接受的媒体类型(MIME-Type)

如果支持WebP,那么Accept中将会包含image/webp这样的字符串

于是乎,我们就可以根据浏览器请求图片资源时的Accept字段来区分是否真正支持WebP格式

为什么不使用User-Agent?

UA一般用于区分浏览器类别、操作系统、网络状况等,通过这些字段区分是否支持WebP,是不可靠的。

举个例子,Edge浏览器第一版是不支持WebP的,现在及以后的版本就会支持了,如果通过UA来区分,成本就会十分高昂

完整的图片请求流程

流程图

图片上传

为了能够支持根据Accept自动返回对应的图片,以达到节省网络带宽,在图片采集上也得进行定制,即:在上传原图(如:PNG、JPG)的同时,还应对图片进行转码,生成对应的WebP文件,并按照一定的规则重命名,以便Image Server查找

如:上传文件为:image.png,保存这个图片的同时,应当再转码一个WebP格式文件,保存为:image.webp或者image.png.webp

那么在请求这个文件的时候,附加一个.webp的扩展名即可

上传时序图

技术框架

由于比较熟悉Node.js,而且它的异步非阻塞I/O能够在有限的资源下,带来良好的性能,所以我在这里选择了Node.js来开发图片服务器(Image Server),其中包括图片上传、转换和路径解析、图片传输模块。当然,选择其他的语言及相关的框架也是完全没有问题的,比如:Java、Go

express

做过Node.js开发的人应该都不陌生,可谓是Node里最著名的Web框架,使用它来构建一个Web服务,并处理HTTP请求的Header、参数(包括上传文件)、路由等十分方便

官网:http://expressjs.com/

Github:https://github.com/expressjs/express/

node-static

node-static用于做静态文件服务器,主要用于根据请求的URL、Accept等参数,返回给客户端(浏览器)所对应的图片,从而实现同一URL,Chrome返回WebP,而Safari/FireFox返回PNG的效果

Github:https://github.com/cloudhead/node-static

为什么不使用Express自带的serve-static?

  1. 查阅node-static的源码,发现它支持的功能更适用,如:断点续传、gzip压缩等

  2. 没有对Express模块的依赖,如果做单独使用,功能支持的比serve-static更好

  3. 性能更好一些

实现

图片解析及传输服务

图片传输服务主要用于向服务器发送请求的客户端传输其能够支持的图片文件流,所以需要实现请求路径的解析和实际文件的匹配,最后将文件流封装在HTTP响应报文当中

这里只需要引入Node自带的urlpath即可完成对请求URL的解析,非常方便

代码如下:

const URL = require('url');
const path = require('path');

const url = URL.parse(req.url);
const pathInfo = path.parse(url.pathname);

path.parse解析所得到的对象继承自ParsedPath类,包含5个字段,rootdirbaseextname,其解释如下

    /**
     * A parsed path object generated by path.parse() or consumed by path.format().
     */
    export interface 
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值