前言
在做很多系统的时候,我们可能都有这样的需求:
在CMS中只维护一张图片,而这张图片在网站的很多地方都需要显示,而且显示的大小不同。
一般做法就是直接使用这张图片,在不同的地方使用 width 和 height 设定图片的显示大小。
场景需求
一般情况下这样做其实就可以了。如下这个场景,如果通过这样做,可能就不太合适了。
场景:CMS 有个海报管理功能,每个大的海报都是一张 1000*2000px 的图片,而且对海报的清晰度有一定的要求,质量不能太差,假定一个海报有 1MB。
然后在网站上有一个海报列表,每页显示20个海报。
这种情况下如果我们还用一张图片,通过 width 和 height 来设定图片显示大小的话,那就太不合适了,一个列表页面下来,20多MB没有了。页面显示肯定会很慢。
解决思路
我们一般的做法有:
1、在CMS中上传一个海报大图,再上传一个海报小图。
2、在CMS中上传一个海报大图,保存的时候,系统自动生成一个海报小图。
3、在CMS中上传一个海报大图,在网页请求图片的时候,附带需求图片的 width 和 height,程序自动判断需求图片是否存在,如果不存在则使用对应的大图生成一个图片响应到客户端。
上面三种做法,1、2 两种情况不够灵活,如果系统还有更多地方需要显示不同尺寸的这样的图片呢?或者系统二期、三期……扩展的时候也有可能有更多尺寸的图片需求呢?
至于第三种方法,相对比较灵活,只有在我们需要的时候才生成。
我们现在需要使用 Apache 来处理我们的静态图片资源。一般情况下 Apache 可不会去管你的图片存在不存在,当我们访问一个新的尺寸图片时,服务器上不存在图片文件,Apache 就直接响应404了。
现在我们要做的就是,让Apache 来判断文件是否存在,如果文件不存在就转而请求我们生成图片的请求。
这样以来,每个尺寸的图片,在需求的时候,第一次 Apache 会交给我们的程序去生成图片,以后这个图片存在了,就全部由Apache 自己管理了。
Apache 配置
下面来说一下 Apache 怎么配置,来实现 “当文件不存在的时候,转发请求到处理程序”。
1、开启 rewrite 模块
去除httpd.conf文件中 #LoadModule rewrite_module modules/mod_rewrite.so 前面的"#"号
2、在 httpd.cnf 中增加配置(没有位置要求,一般我们放在文件最后即可)
我是用的是 apache 2.4 的 VirtualHost ,图片处理程序是用的 Tomcat,所以也给Apache 添加了mod_jk 模块(这个本文不做讲解,可以查看帖子 http://blog.csdn.net/catoop/article/details/47974773)
需要添加的配置内容为:
<IfModule mod_rewrite.c>
RewriteEngine On
# '-s' (is regular file, with size)
# '-l' (is symbolic link)
# '-d' (is directory)
# 'ornext|OR' (or next condition)
# 'nocase|NC' (no case)
# 'last|L' (last rule)
# 'QSA' 追加请求字符串
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-s
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-l
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
#RewriteRule ^(.*)\.[jpg|png|bmp]$ %{HTTP_HOST}/createimage.jsp?path=%{REQUEST_URI} [NC,L]
#RewriteRule ^(.*)\.(jpg|png|bmp)$ createimage.jsp?path=%{REQUEST_URI} [NC,L]
RewriteRule ^(.*)\.(jpg|png|bmp)$ http://shanhyweb.example.com/createimage.jsp?path=%{REQUEST_URI} [NC,L]
#RewriteRule ^(.*)\.(jpg|png|bmp)$ /createimage.jsp?path=%{REQUEST_URI} [NC,L]
</IfModule>
配置可以直接在 httpd.cnf 中添加,也可以在 VirtualHost 中配置,因为我使用的是 VirtualHost 所以我的配置是在 apache2/conf/extra/httpd-vhosts.conf 中,如下:
########################################################
LoadModule jk_module modules/mod_jk.so
Include conf/mod_jk.conf
########################################################
<VirtualHost *:80>
#ServerAdmin webmaster@dummy-host.example.com
DocumentRoot "/svcroot/runtime/webstatic/shanhyweb"
ServerName shanhyweb.example.com
#ServerAlias www.shanhyweb.example.com
ErrorLog "logs/shanhyweb-error_log"
CustomLog "logs/shanhyweb-access_log" common
<IfModule mod_jk.c>
#日志输出文件(其他配置也可以重写mod_jk.conf里面的配置)
JkLogFile logs/mod_jk_shanhyweb.log
#指URL指向如果有servlet,则让worker_web去处理
JkMount /servlet/* worker_web
#指URL为/*.jsp的页面,让worker_web去处理
JkMount /*.jsp worker_web
#指URL为/*.do的页面,让worker_web去处理
JkMount /*.do worker_web
#指URL为/*.json的页面,让worker_web去处理
JkMount /*.json worker_web
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine On
# '-s' (is regular file, with size)
# '-l' (is symbolic link)
# '-d' (is directory)
# 'ornext|OR' (or next condition)
# 'nocase|NC' (no case)
# 'last|L' (last rule)
# 'QSA' 追加请求字符串
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-s
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-l
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteRule ^(.*)\.(jpg|png|bmp)$ http://shanhyweb.example.com/createimage.jsp?path=%{REQUEST_URI} [NC,L]
</IfModule>
<Directory "/svcroot/runtime/webstatic/shanhyweb">
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</VirtualHost>
关于图片的处理,推荐大家可以去了解下 GraphicsMagick 处理图片的。
===========================================
利用这种方法,也可以做其他需求,比如网页的静态化:index.do 用来生成 index.html ,Apache 判断如果有HTML存在就直接响应给浏览器,如果不存在就转发到 index.do 处理生成 index.html
注意:生成图片的这个处理,对同一个图片处理那段代码要做好加锁或同步处理,防止出现高并发情况下,读取和生成图片因为资源占用而出问题的情况。
------------------------------------
(完)