当前位置:首页 » 资源管理 » 静态资源如何存放在nginx中
扩展阅读
利用社会资源做什么好 2025-05-14 10:45:20
怎么查询中石油价 2025-05-14 10:42:22

静态资源如何存放在nginx中

发布时间: 2022-08-12 23:29:28

1. 如何为thinkjs静态资源配置nginx反向代理

最近,用thinkjs写了个小网站,把它放到了VPS上。

为了让网站静态资源加载更快,所以需要在VPS的nginx上配置一个反向代理来直接让Nginx处理静态资源,动态类的请求通过反向代理让Node.js来处理:

?

server {

listen 80;

server_name abc.com www.abc.com;

index index.js index.html index.htm;

if
($host !=
'abc.com'
) {

rewrite ^/(.*)$ http:
//abc.com/$1 permanent;

}

root /www/web/myproject/public_html/www;

if
( -f $request_filename/index.html ){

rewrite (.*) $1/index.html
break
;

}

if
( !-f $request_filename ){

rewrite (.*) /index.js;

}

location = /index.js {

#proxy_http_version 1.1;

proxy_set_header Connection
""
;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_set_header Host $http_host;

proxy_set_header X-NginX-Proxy
true
;

proxy_pass http:
//127.0.0.1:8363$request_uri;

proxy_redirect off;

}

location ~ .*\.(js|css|gif|jpg|jpeg|png|bmp|swf|ico|svg|cur|ttf|woff)$ {

expires 1000d;

}

}

2. 新手问一个nginx动静分离的问题,nginx相较于tomcat更适合处理静态资源,他的原理是需要

需要将tomcat的静态资源部署在nginx上

3. flask 蓝图nginx部署后怎么访问静态资源

能共存,不需要联系的话两个用不一样的端口就行 比如nginx用80,apache用8080 如果都想用8080访问,那么可以把nginx作为apache的前端 两种方法 1、直接用nginx反代的方式 2、静态交给nginx处理,PHP交给apache处理

4. 如何自动复制资源到nginx静态资源服务器

传统的web项目,一般都将静态资源存放在 webroot的目录下,这样做很方便获取静态资源,但是如果说web项目很大,用户很多,静态资源也很多时,服务器的性能 或许就会很低下了。这种情况下一般都会需要一个静态资源的服务器。

搭建nginx服务器首先得安装nginx服务,关于nginx服务的安装可以参考我的另一篇博客《nginx服务安装》这里直接介绍静态服务器的配置
进入nginx安装目录的conf目录下,修改nginx.conf文件,在一个server{}中添加 一个location 部分配置代码如下

root@ubuntu:/usr/local/nginx/conf# vi nginx.conf
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
location /image/ {
root /usr/local/myImage/;
autoindex on;
}

}

从上面的配置可以看出来 端口为80,server_name为localhost(写ip地址也可以)

location /image/ {
root /usr/local/myImage/;
autoindex on;
}

这个配置表示输入 localhost:80/image/ 时会访问本机的/usr/local/myImage/image/ 目录。所以要新建/usr/local/myImage/image/ 目录,同时还要在nginx安装目录的html目录中新建一个 与 location中 image同名的image目录,虽然该目录里面什么也没有,在/usr/local/my Image/image/ 中我们放一张图片1.jpg上去,重启nginx服务,就可以通过 localhost:80/image/1.jpg访问了

root@ubuntu:/usr/local/nginx/html# mkdir image

root@ubuntu:/usr/local/nginx/html# mkdir /usr/local/myImage/image
#放一张照片上去#
root@ubuntu:/usr/local/nginx/html# cd /usr/local/myImage/image
root@ubuntu:/usr/local/myImage/image# ls
1.jpg
root@ubuntu:/usr/local/myImage/image#

重启 nginx

root@ubuntu:/usr/local/nginx/sbin# ./nginx -s reload
root@ubuntu:/usr/local/nginx/sbin#
打开浏览器 输入 server_name:80/image/1.jpg 就可以访问该静态图片

5. 如何判断 ngnix 走了 静态文件路径

Nginx以其消耗资源少,承受并发量大,配置文件简洁等特点,深受广大sa们的喜欢,但是网上传播的nginx 配置并没有对做过多的优化。那么接下来,我就从某大型媒体网站的实际运维nginx优化角度,来给大家讲解一下nginx主要优化的那些方面。

nginx的启动命令是:/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf<br>-c制定配置文件的路径,不加-nginx会自动加载默认路径的配置文件。<br>
停止操作
停止操作是通过向nginx进程发送信号(什么是信号请参阅linux文 章)来进行的
步骤1:查询nginx主进程号
ps -ef | grep nginx
在进程列表里 面找master进程,它的编号就是主进程号了。
步骤2:发送信号
从容停止Nginx:
kill -QUIT 主进程号
快速停止Nginx:
kill -TERM 主进程号
强制停止Nginx:
pkill -9 nginx

另外, 若在nginx.conf配置了pid文件存放路径则该文件存放的就是Nginx主进程号,如果没指定则放在nginx的logs目录下。有了pid文 件,我们就不用先查询Nginx的主进程号,而直接向Nginx发送信号了,命令如下:
kill -信号类型 '/usr/nginx/logs/nginx.pid'

平滑重启
如果更改了配置就要重启Nginx,要先关闭Nginx再打开?不是的,可以向Nginx 发送信号,平滑重启。
平滑重启命令:
kill -HUP 住进称号或进程号文件路径

或者使用

/usr/nginx/sbin/nginx -s reload

注意,修改了配置文件后最好先检查一下修改过的配置文件是否正 确,以免重启后Nginx出现错误影响服务器稳定运行。判断Nginx配置是否正确命令如下:
nginx -t -c /usr/nginx/conf/nginx.conf

或者
/usr/nginx/sbin/nginx -t

平滑升级
如果服务器正在运行的Nginx要进行升级、添加或删除模块时,我们需 要停掉服务器并做相应修改,这样服务器就要在一段时间内停止服务,Nginx可以在不停机的情况下进行各种升级动作而不影响服务器运行。
步骤1:
如 果升级Nginx程序,先用新程序替换旧程序文件,编译安装的话新程序直接编译到Nginx安装目录中。
步 骤2:执行命令
kill -USR2 旧版程序的主进程号或进程文件名
此时旧的Nginx主进程将会把自己的进程文件改名为.oldbin,然后执行新版 Nginx。新旧Nginx会同市运行,共同处理请求。
这时要逐步停止旧版 Nginx,输入命令:
kill -WINCH 旧版主进程号
慢慢旧的工作进程就都会随着任务执行完毕而退出,新版的Nginx的工作进程会逐渐取代旧版 工作进程。

此 时,我们可以决定使用新版还是恢复到旧版。
不重载配置启动新/旧工作进程
kill -HUP 旧/新版主进程号
从容关闭旧/新进程
kill -QUIT 旧/新主进程号
如果此时报错,提示还有进程没有结束就用下面命令先关闭旧/新工作进程,再关闭主进程号:
kill -TERM 旧/新工作进程号

这样下来,如果要恢复到旧版本,只需要上面的几个步 骤都是操作新版主进程号,如果要用新版本就上面的几个步骤都操作旧版主进程号就行了。

上面就是Nginx的一些基本的操作,希望以后Nginx能有更好的方法来处理这些操作, 最好是Nginx的命令而不是向Nginx进程发送系统信号。

一、编译方面优化
1、首先就要从configure 参数分析,根据网上最常用的configure 参数来说,大都是:

# ./configure \
--prefix=/usr/local/nginx \
--user=www \
--group=www \
--with-http_stub_status_mole \
--with-http_ssl_mole

应该说这个参数是通用的,适用于各种环境的需要,比如php环境、纯静态文件环境、代理环境等等。编译nginx程序文件大约有2M大小,跟全面优化的500多K,相差了不少。
下面我们修改一下参数,减少不必要的功能。
纯静态文件环境参数

# ./configure \
--prefix=/usr/local/nginx \
--user=www \
--group=www \
--with-http_stub_status_mole \
--without-http_fastcgi_mole \
--without-http_proxy_mole \
--without-http_upstream_ip_hash_mole \
--without-http_autoindex_mole \
--without-http_ssi_mole \
--without-http_proxy_mole \
--without-mail_pop3_mole \
--without-mail_imap_mole \
--without-mail_smtp_mole \
--without-http_uwsgi_mole \
--without-http_scgi_mole \
--without-http_memcached_mole

去掉了在mail模块fastcgi模块 代理模块 ip_hash模块等,在纯静态文件用不到的模块,现在看看nginx程序文件是不是少了一些。Php环境的话,只需要去掉 --with-http_fastcgi_mole 重新编译即可。代理环境的话,只需要去掉--with_proxy_mole重新编译即可。
2、去掉nginx 默认的debug跟踪设置。这一步需要修改nginx 源码。

# cd nginx-1.0.x
# vim auto/cc/gcc

第175行:前面加#注释掉改行。

#CFLAGS="$CFLAGS -g"

这样的话,编译的参数,就会减少到500多K的标准,这样在大并发量的条件下,性能提升明显。
二、利用google-perftools来优化高并发条件下的nginx
在32位系统下,可以直接安装google-peftools,64位条件下,需要先安装libunwind库。然后再nginx configure 参数增加--with-google_perftools_mole 重新编译安装nginx。
这里以64位环境为准
1. 安装libunwind库

# wget http://download.savannah.gnu.org/releases/libunwind/libunwind-0.99.tar.gz
# tar zxvf libunwind-0.99.tar.gz
# cd libunwind-0.99/
# CFLAGS=-fPIC ./configure –prefix=/usr
# make CFLAGS=-fPIC
# make CFLAGS=-fPIC install

2. 安装google-perftools

# wget http://google-perftools.googlecode.com/files/google-perftools-1.7.tar.gz
# tar xzvf google-perftools-1.7.tar.gz
# cd google-perftools-1.7

然后开始配置:

# ./configure --prefix=/usr --enable-frame-pointers (32位可以不添加--enable-frame-pointers)
# make --j4 && make installnginx

configure 参数加上--with-google-perftools 重新编译nginx

# ./configure \
--prefix=/usr/local/nginx \
--user=www \
--group=www \
--with-http_stub_status_mole \
--without-http_fastcgi_mole \
--without-http_proxy_mole \
--without-http_upstream_ip_hash_mole \
--without-http_autoindex_mole \
--without-http_ssi_mole \
--without-http_proxy_mole \
--without-mail_pop3_mole \
--without-mail_imap_mole \
--without-mail_smtp_mole \
--without-http_uwsgi_mole \
--without-http_scgi_mole \
--without-http_memcached_mole \
--with-google_perftools_mole
# make && make install

3、在nginx.conf 的pid部分下,增加
google_perftools_profiles /data0/google_cache;

# service nginx restart 重启即可生效。
4. 安装

yum -y install gcc gcc-c++ autoconf automake

yum -y install zlib zlib-devel openssl openssl--devel pcre pcre-devel

wget http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm

rpm -ivh nginx-release-centos-6-0.el6.ngx.noarch.rpm

yum install nginx

三、nginx 工作进程优化

nginx指令中的优化(配置文件)

worker_processes 8;
nginx进程数,建议按照cpu数目来指定,一般为它的倍数。

worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;
为每个进程分配cpu,上例中将8个进程分配到8个cpu,当然可以写多个,或者将一个进程分配到多个cpu。

worker_rlimit_nofile 102400;
这个指令是指当一个nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(ulimit -n)与nginx进程数相除,但是nginx分配请求并不是那么均匀,所以最好与ulimit -n的值保持一致。

use epoll;
使用epoll的I/O模型,这个不用说了吧。

worker_connections 102400;
每个进程允许的最多连接数,理论上每台nginx服务器的最大连接数为worker_processes*worker_connections。

keepalive_timeout 60;
keepalive超时时间。

client_header_buffer_size 4k;
客户端请求头部的缓冲区大小,这个可以根据你的系统分页大小来设置,一般一个请求的头部大小不会超过1k,不过由于一般系统分页都要大于1k,所以这里设置为分页大小。分页大小可以用命令getconf PAGESIZE取得。

open_file_cache max=102400 inactive=20s;
这个将为打开文件指定缓存,默认是没有启用的,max指定缓存数量,建议和打开文件数一致,inactive是指经过多长时间文件没被请求后删除缓存。

open_file_cache_valid 30s;
这个是指多长时间检查一次缓存的有效信息。

open_file_cache_min_uses 1;
open_file_cache指令中的inactive参数时间内文件的最少使用次数,如果超过这个数字,文件描述符一直是在缓存中打开的,如上例,如果有一个文件在inactive时间内一次没被使用,它将被移除。

内核参数的优化

net.ipv4.tcp_max_tw_buckets = 6000
timewait的数量,默认是180000。

net.ipv4.ip_local_port_range = 1024 65000
允许系统打开的端口范围。

net.ipv4.tcp_tw_recycle = 1
启用timewait快速回收。

net.ipv4.tcp_tw_reuse = 1
开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接。

net.ipv4.tcp_syncookies = 1
开启SYN Cookies,当出现SYN等待队列溢出时,启用cookies来处理。

net.core.somaxconn = 262144
web应用中listen函数的backlog默认会给我们内核参数的net.core.somaxconn限制到128,而nginx定义的NGX_LISTEN_BACKLOG默认为511,所以有必要调整这个值。

net.core.netdev_max_backlog = 262144
每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。

net.ipv4.tcp_max_orphans = 262144
系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上。如果超过这个数字,孤儿连接将即刻被复位并打印出警告信息。这个限制仅仅是为了防止简单的DoS攻击,不能过分依靠它或者人为地减小这个值,更应该增加这个值(如果增加了内存之后)。

net.ipv4.tcp_max_syn_backlog = 262144
记录的那些尚未收到客户端确认信息的连接请求的最大值。对于有128M内存的系统而言,缺省值是1024,小内存的系统则是128。

net.ipv4.tcp_timestamps = 0
时间戳可以避免序列号的卷绕。一个1Gbps的链路肯定会遇到以前用过的序列号。时间戳能够让内核接受这种“异常”的数据包。这里需要将其关掉。

net.ipv4.tcp_synack_retries = 1
为了打开对端的连接,内核需要发送一个SYN并附带一个回应前面一个SYN的ACK。也就是所谓三次握手中的第二次握手。这个设置决定了内核放弃连接之前发送SYN+ACK包的数量。

net.ipv4.tcp_syn_retries = 1
在内核放弃建立连接之前发送SYN包的数量。

net.ipv4.tcp_fin_timeout = 1
如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间。对端可以出错并永远不关闭连接,甚至意外当机。缺省值是60秒。2.2 内核的通常值是180秒,你可以按这个设置,但要记住的是,即使你的机器是一个轻载的WEB服务器,也有因为大量的死套接字而内存溢出的风险,FIN- WAIT-2的危险性比FIN-WAIT-1要小,因为它最多只能吃掉1.5K内存,但是它们的生存期长些。

net.ipv4.tcp_keepalive_time = 30
当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时。

一个完整的内核优化配置

net.ipv4.ip_forward = 0
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
kernel.sysrq = 0
kernel.core_uses_pid = 1
net.ipv4.tcp_syncookies = 1
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
net.ipv4.tcp_max_tw_buckets = 6000
net.ipv4.tcp_sack = 1
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_rmem = 4096 87380 4194304
net.ipv4.tcp_wmem = 4096 16384 4194304
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.netdev_max_backlog = 262144
net.core.somaxconn = 262144
net.ipv4.tcp_max_orphans = 3276800
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_mem = 94500000 915000000 927000000
net.ipv4.tcp_fin_timeout = 1
net.ipv4.tcp_keepalive_time = 30
net.ipv4.ip_local_port_range = 1024 65000
一个简单的nginx优化配置文件

6. nginx+tomcat 动静态资源怎么部署

http {
include mime.types;
default_type application/octet-stream;
charset utf-8;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';

#access_log logs/access.log main;
# 启用内核复制模式,应该保持开启达到最快IO效率
sendfile on;
#tcp_nopush on;

7. Spring Boot之如何配置静态资源的地址与访

静态资源,例如HTML文件、JS文件,设计到的Spring Boot配置有两项,一是“spring.mvc.static-path-pattern”,一是“spring.resources.static-locations”,很多人都难以分辨它们之间的差异,所以经常出现的结果就是404错误,无法找到静态资源。
1. “spring.mvc.static-path-pattern”
spring.mvc.static-path-pattern代表的含义是我们应该以什么样的路径来访问静态资源,换句话说,只有静态资源满足什么样的匹配条件,Spring Boot才会处理静态资源请求,以官方配置为例:
# 这表示只有静态资源的访问路径为/resources/**时,才会处理请求
spring.mvc.static-path-pattern=/resources/**,
假定采用默认的配置端口,那么只有请求地址类似于“http://localhost:8080/resources/jquery.js”时,Spring Boot才会处理此请求,处理方式是将根据模式匹配后的文件名查找本地文件,那么应该在什么地方查找本地文件呢?这就是“spring.resources.static-locations”的作用了。
2. “spring.resources.static-locations”
“spring.resources.static-locations”用于告诉Spring Boot应该在何处查找静态资源文件,这是一个列表性的配置,查找文件时会依赖于配置的先后顺序依次进行,默认的官方配置如下:
spring.resources.static-locations=classpath:/static,classpath:/public,classpath:/resources,classpath:/META-INF/resources
继续以上面的请求地址为例,“http://localhost:8080/resources/jquery.js”就会在上述的四个路径中依次查找是否存在“jquery.js”文件,如果找到了,则返回此文件,否则返回404错误。
3. 静态资源的Bean配置
从上面可以看出,“spring.mvc.static-path-pattern”与“spring.resources.static-locations”组合起来演绎了nginx的映射配置,如果熟悉Spring MVC,那么理解起来更加简单,它们的作用可以用Bean配置表示,如下:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public-resources/")
.setCacheControl(CacheControl.maxAge(1, TimeUnit.HOURS).cachePublic());
}
}
或者等同与以下的XML。
<mvc:resources mapping="/resources/**" location="/public-resources/">
<mvc:cache-control max-age="3600" cache-public="true"/>
</mvc:resources>
结论
“spring.mvc.static-path-pattern”用于阐述HTTP请求地址,而“spring.resources.static-locations”则用于描述静态资源的存放位置。

8. nginx访问静态资源文件,未指定静态资源的名称怎么办

今天在搭建nginx环境时出现一个奇怪问题,配置的静态资源目录下面文件无法访问,浏览器访问出现403 forbidden,环境是centos7 + nginx 1.6。nginx.conf中http配置如下:

[plain] view plain
……

http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;

upstream tomcat_server {
server 10.10.100.52:8080;
}

server {
listen 80;
charset utf-8;
server_name localhost;

location /fcm/ {
index index.html index.htm;
proxy_pass http://tomcat_server;
proxy_set_header X-Real-IP $remote_addr;
client_max_body_size 100m;
}

location /static/ {
root /home/www/static;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

9. 如何在nginx中缓存静态文件

首先确定配置文件httpd.conf中确已经加载mod_headers模块。LoadMoleheaders_molemoles/mod_headers.so我们可以根据文件类型来让浏览器每次都从服务器读取,这里测试用css、js、swf、php、html、htm这几种文件。HeadersetCache-Control"private,no-cache,no-store,proxy-revalidate,no-transform"HeadersetPragma"no-cache"

10. 缓存静态资源,不知怎么解决

之前看过apach及nginx对于静态资源(含js,图片,css等)部分的缓存,用于加速并减轻后台实际web服务器的压力。
静态资源缓存是WEB服务器优化的一种手段,基本原理如下:
1.客户端浏览器请求服务器一个服务(该服务含有图片,js等静态资源),通常会对于每一个网页中的独立图片或js文件发送一个http请求
2.WEB服务器对于每个资源HTTP请求进行解析,并生成一个资源修改时间的唯一值(可以是etag或last_modified参数),放入服务器端map,key为资源url,value为资源修改时间。最后将此资源修改时间的唯一值包含在http头上返回,因为是首次请求,所以会将所有内容放在http body中一并返回给客户浏览器端
3.客户浏览器接收服服务器响应,并将服务器返回的资源修改时间作为key放入浏览器客户端,value为http body中的实际资源内容
4.客户浏览器再次请求静态资源时,会将资源修改时间一并发送给服务器
5.服务端会从最新的map中取出该资源url对应的修改时间,如果值晚于客户端请求的资源修改时间,这时会返回最新的已经修改过的资源给客户端。否则返回304 not modifed

这里记录资源修改时间的方式有etag及last_modified。最先有的是last_modified,它的工作方式就是上述介绍的,但缺点是只能精确到秒级别。也就是说当你在一秒中修改资源两次,而客户端拿到的是第一次修改,那之后就算客户端第二次再次请求也不会拿到最新的资源。
而etag的出现正是为了解决last_modified的秒级问题,于http 1.1被提出。

今天测试了下,在没有nginx等前端反向代理服务器时,tomcat竟然默认对静态资源做了缓存。
tomcat默认运用etag及last_modifed。etag与if_no_match(客户端浏览器上传时在http head中应该放的属性名)一起使用,last_modified与If-Modified-Since一起使用。

客户端首次请求时,得到请求响应数据如下:

GET http://localhost:8080/webTest/jsp/index.jsp [HTTP/1.1 200 OK 1ms]
GET http://localhost:8080/webTest/js/hello.js [HTTP/1.1 200 OK 1ms]
GET http://localhost:8080/webTest/img/a.jpg [HTTP/1.1 200 OK 2ms]
我们看一下Hello.js这个请求响应具体信息:
server Apache-Coyote/1.1 (表明服务器是tomcat)
Last-Modified: Sun, 11 May 2014 10:54:33 GMT
Etag: W/"175-1399805673000"
Date: Sun, 11 May 2014 10:59:23 GMT
Content-Type: application/javascript;charset=UTF-8
Content-Length: 175
Accept-Ranges: bytes

从上面可以看到tomcat即返回了last_modified也返回了etag。

客户端再次请求时,请求数据如下:
If-None-Match: W/"175-1399805673000"
If-Modified-Since: Sun, 11 May 2014 10:54:33 GMT
响应如下:

GET http://localhost:8080/webTest/jsp/index.jsp [HTTP/1.1 200 OK 1ms]
GET http://localhost:8080/webTest/js/hello.js [HTTP/1.1 304 Not Modified 1ms]
GET http://localhost:8080/webTest/img/a.jpg [HTTP/1.1 304 Not Modified 1ms]
从中我们可以看到tomcat对于静态数据作了缓存。

接着我们分析tomcat对于这部分静态缓存的判断处理,这部分逻辑是写在DefaultServlet类中,
我们可以在doGet方法中进入ServiceContext方法中找到以下源码:
// Check if the conditions specified in the optional If headers are
// satisfied.
if (cacheEntry.context == null) {

// Checking If headers
boolean included =
(request.getAttribute(Globals.INCLUDE_CONTEXT_PATH_ATTR) != null);
if (!included
&& !checkIfHeaders(request, response, cacheEntry.attributes)) { //这句判断是否需要返回整个资源请求
return;
}

}
上面源码的 if (!included
&& !checkIfHeaders(request, response, cacheEntry.attributes))
用于判断是否需要返回整个资源,如果indcluded与checkIfHeaders方法返回的都是false,这时就直接返回,说明资源未修改,或者是缓存不支持的请求方式。
我们接着查看checkIfHeaders方法:
/**
* Check if the conditions specified in the optional If headers are
* satisfied.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
* @param resourceAttributes The resource information
* @return boolean true if the resource meets all the specified conditions,
* and false if any of the conditions is not satisfied, in which case
* request processing is stopped
*/
protected boolean checkIfHeaders(HttpServletRequest request,
HttpServletResponse response,
ResourceAttributes resourceAttributes)
throws IOException {

return checkIfMatch(request, response, resourceAttributes)
&& checkIfModifiedSince(request, response, resourceAttributes)
&& checkIfNoneMatch(request, response, resourceAttributes)
&& checkIfUnmodifiedSince(request, response, resourceAttributes);

}

可以看到tomcat只有当这四个属性全部返回true(也就是说全部认为资源已经改变)才会返回true,这样最终会将整个资源(最新修改过的)返回客户端。
在这里,我们从上面实际过程当中看到,浏览器第二次请求资源时在http请求header中放了
If-None-Match: W/"175-1399805673000"
If-Modified-Since: Sun, 11 May 2014 10:54:33 GMT
这两个属性。
因此我们查看
&& checkIfModifiedSince(request, response, resourceAttributes)
&& checkIfNoneMatch(request, response, resourceAttributes)
这两个方法
checkIfModifiedSince源码如下:
/**
* Check if the if-modified-since condition is satisfied.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
* @param resourceInfo File object
* @return boolean true if the resource meets the specified condition,
* and false if the condition is not satisfied, in which case request
* processing is stopped
*/
protected boolean checkIfModifiedSince(HttpServletRequest request,
HttpServletResponse response,
ResourceAttributes resourceAttributes) {
try {
long headerValue = request.getDateHeader("If-Modified-Since");
long lastModified = resourceAttributes.getLastModified();
if (headerValue != -1) {

// If an If-None-Match header has been specified, if modified since
// is ignored.
if ((request.getHeader("If-None-Match") == null)
&& (lastModified < headerValue + 1000)) {
// The entity has not been modified since the date
// specified by the client. This is not an error case.
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
response.setHeader("ETag", resourceAttributes.getETag());

return false;
}
}
} catch (IllegalArgumentException illegalArgument) {
return true;
}
return true;

}
源码中可以看到:
if ((request.getHeader("If-None-Match") == null)
&& (lastModified < headerValue + 1000)) {
这句话表明只有在客户端浏览器发送的请求头中不包含If-None-Match,IfModifiedSince才会生效。
我们接着看checkIfNoneMatch,源码如下:
/**
* Check if the if-none-match condition is satisfied.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
* @param resourceInfo File object
* @return boolean true if the resource meets the specified condition,
* and false if the condition is not satisfied, in which case request
* processing is stopped
*/
protected boolean checkIfNoneMatch(HttpServletRequest request,
HttpServletResponse response,
ResourceAttributes resourceAttributes)
throws IOException {

String eTag = resourceAttributes.getETag();
String headerValue = request.getHeader("If-None-Match");
if (headerValue != null) {

boolean conditionSatisfied = false;

if (!headerValue.equals("*")) {

StringTokenizer commaTokenizer =
new StringTokenizer(headerValue, ",");

while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
String currentToken = commaTokenizer.nextToken();
if (currentToken.trim().equals(eTag))
conditionSatisfied = true;
}

} else {
conditionSatisfied = true;
}

if (conditionSatisfied) {

// For GET and HEAD, we should respond with
// 304 Not Modified.
// For every other method, 412 Precondition Failed is sent
// back.
if ( ("GET".equals(request.getMethod()))
|| ("HEAD".equals(request.getMethod())) ) {
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
response.setHeader("ETag", eTag);

return false;
}
response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
return false;
}
}
return true;

}
这里:
String eTag = resourceAttributes.getETag();
String headerValue = request.getHeader("If-None-Match");
这两句比较简单,就是分别从服务器缓存和http请求头中中取出etag。
接着判断这两个etag如果相等,则conditionSatisfied为true,会执行到以下语句:
if (conditionSatisfied) {

// For GET and HEAD, we should respond with
// 304 Not Modified.
// For every other method, 412 Precondition Failed is sent
// back.
if ( ("GET".equals(request.getMethod()))
|| ("HEAD".equals(request.getMethod())) ) {
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
response.setHeader("ETag", eTag);

return false;
}
response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
return false;
}
这段语句中可以发现,如果资源未改变的情况下,并且请求方式为GET或者HEAD时,会返回304状态码。否则返回一个412状态码,同样不会返回资源内容。
如果上述最终
if ((request.getHeader("If-None-Match") == null)
&& (lastModified < headerValue + 1000))
条件不成立,即资源更新了或者是第一次请求,这里会读取当前请求资源文件,并最终放入http响应中。