redirect和forward区别

一、edirect和forward的定义:

    1.redirect:服务端发送给客户端一个重定向的临时响应头,这个响应头包含重定向之后的URL,客户端用新的URL重新向服务器发送一个请求。

    2.forward:服务器程序内部请求转向,这个特性允许前一个程序用于处理请求,而后一个程序用来返回响应。

    定义说明转发操作可以保持request内的parameter,attribute这些值都可以保留,而重定向操作却会丢弃:第一:转发实在服务端完成,并没有经过客户端;第二:转发整个操作完成后才生成响应;第三:重定向是服务端向客户端发送指定的URL;第四:重定向实在客户端完成的。


二、sendRedirect

    1.代码分析:

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的临时响应头,“SC_FOUND”的值是302,

就是重定向临时响应头的状态码。如果传入的“location”值不合法,就包装一个404的响应头。浏览器最终再发起新的请求,最终展现在浏览器中的即为新请求的URL。这些并不能造成重定向操作将之前request中已经绑定的一系列parameter和attribute丢掉,最根本的原因是一个请求完整处理完成之后,整个请求会有一个release的过程,即CoyoteAdapter的service方法执行完的finally块中执行release这一过程,如下:

finally {
     if (!comet && !async || error.get()) {
        request.recycle();  //注意这两行代码
      response.recycle();
    } 
}

request中recycle方法:

/**
 * Release all object references, and initialize instance variables, in preparation for reuse of this object.
 */
public void recycle() {
    attributes.clear();
    requestedSessionId = null;
    requestedSessionURL = false;
    parameterMap.clear();
    pathParameters.clear();
}

用于存储setAttribute()方法设置的和setParameter()方法设置的数据在这里都clear清理了。

    2.参数

    redirect在用户的浏览器端工作,sendRedirect()可以带参数传递,比如没有Test?sid=asd传至下个页面,同时它可以重定向至不同的主机上,且在浏览器地址栏上会出现重定向页面的URL。

    public void sendRedirect(java.long.String location) throws java.io.IOException

    这个方法将响应定向到参数location指定的、新的URL。location可以是一个绝对的URL,也可以使用相对的URL。如果location以“/”开头,则容器认为相对于当前web应用的根,否则,容器将解析为相对于当前请求的URL。这种重定向的方法,将导致客户端浏览器的请求URL跳转。从浏览器中的地址栏中可以看到新的URL地址。

三、forward

    1.代码分析

    request.getRequestDispatcher("/hello.jsp").forward(request,response);

forward方法内部最终会调用dispatcher的doForward方法

void doForward(ServletRequest request, ServletResponse response){
    // Set up to handle the specified request and response
    State state = new State(request, response, false);
    wrapResponse(state);
        ApplicationHttpRequest wrequest =
            (ApplicationHttpRequest) wrapRequest(state); 
        String contextPath = context.getPath();
        HttpServletRequest hrequest = state.hrequest;
        if (hrequest.getAttribute(
                RequestDispatcher.FORWARD_REQUEST_URI) == null) {
            wrequest.setAttribute(RequestDispatcher.FORWARD_PATH_INFO,hrequest.getPathInfo());
            wrequest.setAttribute(RequestDispatcher.FORWARD_QUERY_STRING, hrequest.getQueryString());}
        wrequest.setContextPath(contextPath);
        wrequest.setRequestURI(requestURI);
        wrequest.setServletPath(servletPath);
        wrequest.setPathInfo(pathInfo);
        if (queryString != null) {
            wrequest.setQueryString(queryString);
            wrequest.setQueryParams(queryString);
        }

        processRequest(request,response,state); //进行第二个资源的请求
    }
}

    第二个资源的请求处理与一般的请求处理类似,只是在第一个请求之上,并没有返回响应时继续发起第二个请求,此时第一个请求的各类参数会继续向后传递,最终数据全部处理完成之后,整个响应发送回客户端。

    2.参数

    RequestDispatcher.forward()实在服务器端起作用,当使用forward()时,Servletengine传递HTTP请求从当前Servlet orJSP到另一个Servlet,JSP或普通HTML文件,也即form提交至a.jsp,在a.jsp用到了forward()重定向至b.jsp,此时form提交的所有信息在b.jsp都可以获得,参数自动传递,但forward()无法重定向至有frame的jsp文件,可以重定向至有frame的html文件,同时forward()无法在后面带参数传递,比如myTest()?sid=45345,这样不行,可以程序内通过response.setAttribute("sid","45345")来传至下一个页面,转发后浏览器地址栏URL不变。

四、如何选择

    RequestDispatcher.forward()方法和HttpServletResponse.sendRedirect()方法的区别是:前者仅是容器中控制权的转向,在客户端浏览器地址栏中不会显示出转向后的地址;后者则是完全的跳转,浏览器将会得到跳转的地址,并重新发送请求链接。这样,从浏览器的地址栏中可以看到跳转后的链接地址。所以,前者更加高效,在前者可以满足需要时,尽量使用RequestDispatcher.forward()方法,并且这样也有助于隐藏实际的链接。在有些情况下,需要跳转到一个其它服务器上的资源,则必须使用HttpServletResponse.sendRedirect()方法。


猜你喜欢

转载自blog.csdn.net/chaoyue1861/article/details/80241607