Web---字节输出流和字符输出流的共存问题、转发、重定向、请求包含知识点讲解

简介: 本章博客的知识点:1、字节输出流和字符输出流的共存问题 2、转发时,两个servlet都输出信息的问题 详细知识,见OneServlet和TwoServlet源代码中的注释 转发:传参,访问顺序(doGet还是doPost) 3、重定向:传参,访问顺序(doGet还是doPost) 4、请求包含:传参,访问顺序(doGet还是doPost)有些演示,不怎么好分段用博客写处理,如果想加深理解的,最好自己取写一遍。

本章博客的知识点:

1、字节输出流和字符输出流的共存问题
2、转发时,两个servlet都输出信息的问题
详细知识,见OneServlet和TwoServlet源代码中的注释
转发:传参,访问顺序(doGet还是doPost)
3、重定向:传参,访问顺序(doGet还是doPost)
4、请求包含:传参,访问顺序(doGet还是doPost)

有些演示,不怎么好分段用博客写处理,如果想加深理解的,最好自己取写一遍。

1、字节输出流和字符输出流的共存问题

index.jsp:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>

<body>
    <!--   1、字节输出流和字符输出流的共存问题---不能共存(跟get或post方式没关系)。即

        :在同一个servlet响应中,不能同时采两种输出流。
        另外:如果要用字节流输出中文,用write(byte[])方法 -->
    <a href="servlet/OutServlet">字节输出流和字符输出流的共存问题</a>
    <form action="servlet/OutServlet" method="post">
        <input type="text" name="name" /><br /> 
        <input type="submit"value="提交" />
    </form>

</body>
</html>

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <display-name></display-name>
  <servlet>
    <servlet-name>OutServlet</servlet-name>
    <servlet-class>cn.hncu.servlet.OutServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>OutServlet</servlet-name>
    <url-pattern>/servlet/OutServlet</url-pattern>
  </servlet-mapping>    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

OutServlet.java:

package cn.hncu.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class OutServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        //1、用字节输出流向客户端写信息
        ServletOutputStream out = response.getOutputStream();//获取字节输出流

        out.print("HELLO--doGet");//全部写英文是没有问题的
        //out.print("你好");//500错误。出异常,因为内部是用iso8859-1读取,已经写死了,因此中文不行
        out.write("你好".getBytes("utf-8"));//如果中文要用字节流输出,用write(byte[])方法,而且最好给编码方式


        //2、同时用字符输出流向客户端写信息-也是出现500错误。
        PrintWriter out2 = response.getWriter();
        out2.print("hello,你好");

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        //1、用字节输出流向客户端写信息
        ServletOutputStream out = response.getOutputStream();//获取字节输出流

        out.print("HELLO--doGet");//全部写英文是没有问题的
        //out.print("你好");//500错误。出异常,因为内部是用iso8859-1读取,已经写死了,因此中文不行
        out.write("你好".getBytes("utf-8"));//如果中文要用字节流输出,用write(byte[])方法,而且最好给编码方式


        //2、同时用字符输出流向客户端写信息-也是出现500错误。
        PrintWriter out2 = response.getWriter();
        out2.print("hello,你好");

    }

}

小总结:

大家自己写的时候,注意知道把哪里注释了,同时写了response.getOutputStream();//获取字节输出流和response.getWriter();-是不能共存的,也就是说,只能写其中一个!!!

2、转发时,两个servlet都输出信息的问题、传参,访问顺序(doGet还是doPost)

详细知识,见OneServlet和TwoServlet源代码中的注释

index.jsp:

    <a href="servlet/OneServlet">转发时,两个servlet都输出信息的问题、传参问题、访问顺序问题</a><br /> 
    <form action="servlet/OneServlet" method="post">
        <input type="text" name="name" /><br /> 
        <input type="submit"value="提交" />
    </form>

web.xml:

<servlet>
    <servlet-name>OneServlet</servlet-name>
    <servlet-class>cn.hncu.servlet.OneServlet</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>TwoServlet</servlet-name>
    <servlet-class>cn.hncu.servlet.TwoServlet</servlet-class>
  </servlet>
<servlet-mapping>
    <servlet-name>OneServlet</servlet-name>
    <url-pattern>/servlet/OneServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>TwoServlet</servlet-name>
    <url-pattern>/servlet/TwoServlet</url-pattern>
  </servlet-mapping>    

OneServlet.java:

package cn.hncu.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class OneServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("你好...OneServlet...");

        //out.flush();
//Tomcat对于同response,只输出一次(把缓存中的内容刷出去)。刷了(close也一样),流就关闭了,下面的转发就无法进行了,因为此时response已经提交了(整个转发链只会响应一次,即提交了)

        //传参---设置属性(只要key不同,随便存几个)---放入request对象中
        request.setAttribute("age", "23-OneServlet");

        RequestDispatcher rd = request.getRequestDispatcher("/servlet/TwoServlet");
        rd.forward(request, response);
    }


    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("你好...OneServlet...");

        //out.flush();
//Tomcat对于同response,只输出一次(把缓存中的内容刷出去)。刷了(close也一样),流就关闭了,下面的转发就无法进行了,因为此时response已经提交了(整个转发链只会响应一次,即提交了)

        //传参---设置属性(只要key不同,随便存几个)---放入request对象中
        request.setAttribute("age", "23-OneServlet");

        RequestDispatcher rd = request.getRequestDispatcher("/servlet/TwoServlet");
        rd.forward(request, response);

    }

}

TwoServlet.java:

package cn.hncu.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TwoServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");//如果前一个转发过来的Servlet已经设了,可以不用再写

        PrintWriter out = response.getWriter();
        out.println("get...<br/>");
        out.print("周末愉快。。。<br/>");
        //第二个servlet会先把缓存中之前的内容情空,然后再把当前servlet的输出内容写入缓存,刷出去。

        String name = (String) request.getAttribute("age");
        out.print("name:"+name+"<br/>");
        out.flush();//写在这里是没有什么影响的

    }


    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");//如果前一个转发过来的Servlet已经设了,可以不用再写

        PrintWriter out = response.getWriter();
        out.println("post...<br/>");
        out.print("周末愉快。。。<br/>");
        //第二个servlet会先把缓存中之前的内容情空,然后再把当前servlet的输出内容写入缓存,刷出去。

        String name = (String) request.getAttribute("age");
        out.print("name:"+name+"<br/>");
        out.flush();//写在这里是没有什么影响的

    }

}

小总结:

转发时,两个servlet都输出信息的问题
详细知识,见OneServlet和TwoServlet源代码中的注释
传参,访问顺序(doGet还是doPost) —转发是共享同一个request和同一个response对象的
1)第一个是doGet,第二个走的也是doGet
2)第一个是doPost,第二个走的也是doPost
(因为request传过来的参数一样,访问方式也是一样的)
3)传参:可以通过request.setAttribute()设置,通过request.getAttribute()获取 —doGet或doPost都一样

3、重定向:传参,访问顺序(doGet还是doPost)

index.jsp:

<a href="servlet/RedirOneServlet">重定向时,两个servlet都输出信息的问题、传参问题、访问顺序问题</a><br /> 
    <form action="servlet/RedirOneServlet" method="post">
        <input type="text" name="name" /><br /> 
        <input type="submit"value="提交" />
    </form>

web.xml:

<servlet>
    <servlet-name>RedirOneServlet</servlet-name>
    <servlet-class>cn.hncu.servlet.RedirOneServlet</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>RedirTwoServlet</servlet-name>
    <servlet-class>cn.hncu.servlet.RedirTwoServlet</servlet-class>
  </servlet>
<servlet-mapping>
    <servlet-name>RedirOneServlet</servlet-name>
    <url-pattern>/servlet/RedirOneServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>RedirTwoServlet</servlet-name>
    <url-pattern>/servlet/RedirTwoServlet</url-pattern>
  </servlet-mapping>

RedirOneServlet.java:

package cn.hncu.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class RedirOneServlet extends HttpServlet {


    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("11111111111");//这是一个无效的输出,我们看不到!!

        response.sendRedirect("/myServletDemo4/servlet/RedirTwoServlet");
    }


    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("11111111111");//这是一个无效的输出,我们看不到!!
        //out.flush();
        //如果刷了,后面就不能故去了。
        String name = request.getParameter("name");
        System.out.println("11111para-name:"+name);//这个也只有这里能接收到,如果想要传过去,得通过 地址栏+?+name= 的方式,如最后一行
        request.setAttribute("age", 23);//这一句是没用的,对方收不到!

        //response.sendRedirect("/myServletDemo4/servlet/RedirTwoServlet");
        response.sendRedirect("/myServletDemo4/servlet/RedirTwoServlet?name="+name+"&age=23");
    }

}

RedirTwoServlet.java:

package cn.hncu.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class RedirTwoServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("doget........22222222<br/>");

        String name = request.getParameter("name");
        out.print("2222para-name:"+name);
        String age = request.getParameter("age");
        out.print("<br/>2222para-age:"+age);
        //得到地址栏?号后的属性值

        Integer age2 = (Integer) request.getAttribute("age");
        out.print("<br>attr-age:"+age2);//null. web.xml 中没有设置

    }


    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("doget........22222222<br/>");
    }

}

小总结:

两个servlet都输出信息的问题,这里和转发的情况其实可以理解是相同的,你第一个servlet如果out调用flush(),一样的,不会再重定向到后面的第二个servlet中去了。

1)无论第一个是doGet还是doPost,第二个走的都是doGet
(可以理解成:通过地址栏访问的)
2)传参:第二个servlet中的request和第一个是完全不同的对象,因此无法通过:request.setAttribute()和request.getAttribute() 实现传参。

3)第二个servlet中是无法通过request.getParameter()的方式获取页面提交的参数数据

4)重定向方式下,如果要进行传参,可采用:在地址栏的url后添加类似如下的格式传参:?name=Jack&age=23

注意,采用地址栏url传参的方式,在浏览器地址栏是能够看到的,因此要注意隐私(安全)问题—如果有隐私参数,那么要加密!!!
5)转发只能在站内进行(路径默认在项目内,即路径不用带项目名),重定向可以在站外进行(如果是站外路径要带“http://”开头,站内路径要带项目名)。如果非要项目之间(站外)进行跳转,那么必须要选择重定向。

4、请求包含:传参,访问顺序(doGet还是doPost)

index.jsp:

<a href="servlet/IncludeOneServlet">请求包含时,两个servlet都输出信息的问题、传参问题、访问顺序问题</a><br /> 
    <form action="servlet/IncludeOneServlet" method="post">
        <input type="text" name="name" /><br /> 
        <input type="submit"value="提交" />
    </form>

web.xml:

 <servlet>
    <servlet-name>IncludeOneServlet</servlet-name>
    <servlet-class>cn.hncu.servlet.IncludeOneServlet</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>IncludeTwoServlet</servlet-name>
    <servlet-class>cn.hncu.servlet.IncludeTwoServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>IncludeOneServlet</servlet-name>
    <url-pattern>/servlet/IncludeOneServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>IncludeTwoServlet</servlet-name>
    <url-pattern>/servlet/IncludeTwoServlet</url-pattern>
  </servlet-mapping>    

IncludeOneServlet.java:

package cn.hncu.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class IncludeOneServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("<html><body>");
        out.print("Include111111..doGet...");

        //传参,和转发时一样的!
        request.setAttribute("age", 25);

        RequestDispatcher rd = request.getRequestDispatcher("/servlet/IncludeTwoServlet");
        rd.include(request, response);
        //它的机制可理解成函数调用。相当于把第二个servlet的doGet()方法中的代码拷到这里来运行。

        //后面的还可以继续运行!!!
        out.print("<br/>Include11111...daGet...请求包含之后!");

        out.print("</body></html>");


    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("<html><body>");
        out.print("Include111111..doPost...");

        //传参,和转发时一样的!
        request.setAttribute("age", 25);

        RequestDispatcher rd = request.getRequestDispatcher("/servlet/IncludeTwoServlet");
        rd.include(request, response);
        //它的机制可理解成函数调用。相当于把第二个servlet的doPost()方法中的代码拷到这里来运行。

        //后面的还可以继续运行!!!
        out.print("<br/>Include11111...doPost...请求包含之后!");

        out.print("</body></html>");


    }

}

IncludeTwoServlet.java

package cn.hncu.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class IncludeTwoServlet extends HttpServlet {


    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        //因为上一个servlet已经设过,这里可以不设
        PrintWriter out = response.getWriter();
        //out.print("<html><body>");

        out.print("<br/>Include222222中文...doGet");

        //接参
        Integer age = (Integer) request.getAttribute("age");

        out.print("<br/>Include222222...doGet...:"+age);

        //下面这两句会导致无穷递归
        //RequestDispatcher rd = request.getRequestDispatcher("/servlet/IncludeOneServlet");
        //rd.include(request, response);



        //out.print("</body></html>");

    }


    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        //因为上一个servlet已经设过,这里可以不设
        PrintWriter out = response.getWriter();
        //

        out.print("<br/>Include222222中文...doPost");

        //接参
        Integer age = (Integer) request.getAttribute("age");

        out.print("<br/>Include222222...doPost...:"+age);

    }

}

小总结:

1)两个servlet的输出都有效!—中途调用flush,流不会关闭,后续的输出都会执行。如果在第一个servlet中执行了out.close(),那么后续的输出(无论是第一还是第二个servlet)都不会执行,但程序不会出异常!!!!
2)第一个是doGet,第二个走的也是doGet
3)第一个是doPost,第二个走的也是doPost
4)对于请求包含,第二个servlet在执行完之后,还会回到第一个servlet的rd.include()这行代码之后。
5)传参方面,和转发是完全一样的,因为都是共享同一个request和同一个response.
6)页面输出时,注意html标签不要输出冲突,如:在第一个servlet中输出了“<html><body>”和“</body></html>”,同时在第二个servlet中也输出这些标记。这样会出现html标记嵌套冲突!!
※重定向和转发:跳转之后不会回到原来的那个servlet中。
而“请求转发”在跳转之后会回到原来servlet的“rd.include()”这句代码之后继续执行。

演示:

可以看到,客户端只请求了一次!!!转发是请求两次的。

如果2个服务器都向客户端输出了<html><body> </body></html>

会出现:

目录
相关文章
|
3月前
|
开发框架 缓存 .NET
并发请求太多,服务器崩溃了?试试使用 ASP.NET Core Web API 操作筛选器对请求进行限流
并发请求太多,服务器崩溃了?试试使用 ASP.NET Core Web API 操作筛选器对请求进行限流
209 0
|
22天前
|
前端开发 开发者
WEB自定义页面请求响应
Web组件支持在应用拦截到页面请求后自定义响应请求能力。开发者通过onInterceptRequest()接口来实现自定义资源请求响应 。自定义请求能力可以用于开发者自定义Web页面响应、自定义文件资源响应等场景。
22 0
|
1月前
|
监控 安全 Apache
构建安全的URL重定向策略:确保从Web到App平滑过渡的最佳实践
【10月更文挑战第2天】URL重定向是Web开发中常见的操作,它允许服务器根据请求的URL将用户重定向到另一个URL。然而,如果重定向过程没有得到妥善处理,可能会导致安全漏洞,如开放重定向攻击。因此,确保重定向过程的安全性至关重要。
71 0
|
2月前
|
SQL 存储 安全
Web安全-CSRF跨站请求伪造
Web安全-CSRF跨站请求伪造
84 5
|
3月前
|
Web App开发 安全 JavaScript
【Azure 应用服务】App Service 通过配置web.config来添加请求返回的响应头(Response Header)
【Azure 应用服务】App Service 通过配置web.config来添加请求返回的响应头(Response Header)
|
3月前
|
缓存 运维 网络协议
一台新PC进行Web页面请求的历程:技术深度剖析
【8月更文挑战第24天】在当今数字化时代,当我们轻轻点击浏览器上的一个链接,背后其实经历了一场复杂而精妙的交互过程。本文将带您深入探索,从一台全新PC的角度出发,揭秘Web页面请求的全过程,展现这背后隐藏的技术奥秘。
33 0
|
3月前
|
API
【Azure API 管理】在 Azure API 管理中使用 OAuth 2.0 授权和 Azure AD 保护 Web API 后端,在请求中携带Token访问后报401的错误
【Azure API 管理】在 Azure API 管理中使用 OAuth 2.0 授权和 Azure AD 保护 Web API 后端,在请求中携带Token访问后报401的错误
|
5月前
|
JSON 前端开发 Java
一文读Web开发 之接口后端接口、类与前端请求、拦截器编写
一文读Web开发 之接口后端接口、类与前端请求、拦截器编写
153 6
|
1月前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
101 3
|
18天前
|
设计模式 前端开发 数据库
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第27天】本文介绍了Django框架在Python Web开发中的应用,涵盖了Django与Flask等框架的比较、项目结构、模型、视图、模板和URL配置等内容,并展示了实际代码示例,帮助读者快速掌握Django全栈开发的核心技术。
108 45