Nginx服务器内部重定向

Java web编程中经常涉及到重定向的问题,servlet实现了两种重定向的方式:服务器内部重定向(也叫forward,请求转发),和客户端重定向(redirect)。

forward是服务端行为,还是一个完整的http请求,对用户来说是透明的;而redirect是客户端的重定向,用户能明显看见url发生了改变,因为服务端在第一次的http响应中发送的是一个跳转请求,可以是发送一个301或302的http响应,在http头中指定location即可,也可以是200响应,在html中设置<meta http-equiv="refresh" content="0;url=xxx">标签,指定跳转的url即可。servlet的实现方式是定义了302状态码,指定location来实现跳转。

大多数的web应用服务器都会在前端加上一个nginx作为反向代理层,目地为了安全或者负载均衡,nginx对于静态文件的处理能力比较高效,往往会有这种需求:由web应用服务器做动态的下载权限的验证,然后把下载的事情交给nginx去做,同时又不想直接把文件地址暴露给用户,于是必须使用到nginx服务端重定向的技术。回想一下nginx本身做反向代理的能力,设置一个proxy_pass,本身就起到了隐藏背后url的功能,只不过是写死在配置文件中的,这里的需求是一个下载请求过来以后,web应用服务器处理完验证逻辑后才代理到其他的url,所以这个代理的请求必须由web应用服务器自己来发。

nginx提供了X-Accel-Redirect的关键字,web应用服务器只要在响应的header中加上X-Accel-Redirect字段,值为跳转的uri,nginx会自动拦截这个http响应,然后在内部重定向到这个uri的位置,同时nginx必须配置internal的proxy_pass,表示这个反向代理只被内部使用,用户直接访问这个uri,会404。

1
2
3
4
5
6
7
8
9
10
11
server{
listen 80;
server_name localhost;
location /protect {
proxy_pass http://www.qq.com;
internal;
}
location / {
proxy_pass http://127.0.0.1:8089/;
}
}

比如请求http://localhost/test, 应用服务器在test处理结尾加上

1
response.addHeader("X-Accel-Redirect", "/protect")

浏览器会返回www.qq.com的首页,而url仍然是http://localhost/test, 即实现nginx服务器内部重定向。