-
sendRedirect(客户端作的重定向)
该方法通过修改HTTP协议的Header部分,对浏览器下达重定向指令,让浏览器对在location中指定的URL提出请求,使浏览器重定向网页的内容。
public void sendRedirect(String location)
throws IOException {
if (isCommitted())
throw new IllegalStateException
(sm.getString("coyoteResponse.sendRedirect.ise"));
// Ignore any call from an included servlet
if (included)
return;
// Clear any data content that has been buffered
resetBuffer();
// Generate a temporary redirect to the specified location
try {
String absolute = toAbsolute(location);
setStatus(SC_FOUND);
setHeader("Location", absolute);
} catch (IllegalArgumentException e) {
setStatus(SC_NOT_FOUND);
}
// Cause the response to be finished (from the application perspective)
setSuspended(true);
}
该方法可以接受绝对的或者相对的URL。
如果传递到该方法的参数是一个相对的URL,那么web container在将它发送到客户端前会把它转换成一个绝对的URL。
protected String toAbsolute(String location) {
boolean leadingSlash = location.startsWith("/");
if (location.startsWith("//")) {
String scheme = request.getScheme();
try {
redirectURLCC.append(scheme, 0, scheme.length());
redirectURLCC.append(':');
redirectURLCC.append(location, 0, location.length());
return redirectURLCC.toString();
} catch (IOException e) {
。。。。
}
} else if (leadingSlash || !hasScheme(location)) {
redirectURLCC.recycle();
String scheme = request.getScheme();
String name = request.getServerName();
int port = request.getServerPort();
try {
redirectURLCC.append(scheme, 0, scheme.length());
redirectURLCC.append("://", 0, 3);
redirectURLCC.append(name, 0, name.length());
if ((scheme.equals("http") && port != 80)
|| (scheme.equals("https") && port != 443)) {
redirectURLCC.append(':');
String portS = port + "";
redirectURLCC.append(portS, 0, portS.length());
}
if (!leadingSlash) {
String relativePath = request.getDecodedRequestURI();
int pos = relativePath.lastIndexOf('/');
CharChunk encodedURI = null;
final String frelativePath = relativePath;
final int fend = pos;
if (SecurityUtil.isPackageProtectionEnabled() ){
try{
encodedURI = AccessController.doPrivileged(
new PrivilegedExceptionAction<CharChunk>(){
@Override
public CharChunk run() throws IOException{
return urlEncoder.encodeURL(frelativePath, 0, fend);
}
});
} catch (PrivilegedActionException pae){
。。。。。。
}
} else {
encodedURI = urlEncoder.encodeURL(relativePath, 0, pos);
}
redirectURLCC.append(encodedURI);
encodedURI.recycle();
redirectURLCC.append('/');
}
redirectURLCC.append(location, 0, location.length());
normalize(redirectURLCC);
} catch (IOException e) {
。。。。。
}
return redirectURLCC.toString();
} else {
return (location);
}
}
getServerPort(), getLocalPort(), and getRemotePort()的具体含义
getLocalPort():获取的是应用服务器的端口,即该应用的实际端口,无论请求经过了多少代理,转发,getLocalPort只取最后的端口,也就是应用的端口
getServerPort():获取的是URL请求的端口,比如你的请求时127.0.0.1:8080,应用服务器的端口是80,那么getServerPort得到的端口是8080。而getLocalPort得到的是80。
getRemotePort():发出请求的客户端的端口号。
端口映射问题
外网90端口,在内网80端口,内网的nginx配置代理端口,后端服务器中request.getServerPort()无法获得正确的端口,返回的仍然是80,在response.sendRedirect()时,客户端可能无法获得正确的重定向url。解决方式:修改nginx配置。
在使用response.sendRedirect时,前面不能有HTML被送到浏览器。事实上现在的server都有cache机制,一般在8k(jsp server),这意味着除非关闭cache,或者使用了out.flush()强制刷新,那么在使用sendRedirect之前,可以允许有少量HTML输出。。在response.sendRedirect()之后应该紧跟一句return;因为转向后的输出可能导致转向失败。
2.forward (服务器端作的重定向)
服务器往client发送数据的过程为:服务器在向客户端发送数据之前,是先将数据输出到缓冲区,然后将缓冲区中数据发送给client端。