转发和重定向的区别及其原理

news2024/11/15 12:10:43

在web应用中完成资源的跳转

在一个web应用中完成资源的跳转可以通过转发或者重定向两种方式, 跳转的资源只要是服务器内部合法的资源即可(如Servlet、JSP、HTML…)

  • 转发机制使用场景: 某个Servlet向request域当中绑定了数据,希望从其他Servlet当中把request域里面的数据取出来
  • 重定向使用场景: 除转发外剩余的所有的请求
方法名功能
request.getRequestDispatcher(“/要转发的路径且不含项目名”).forward(request, response);转发是服务器内部完成资源的跳转(转发路径不加项目名)
response.sendRedirect(request.getContextPath() + “转发的路径”);重定是浏览器发起一次全新的请求(转发路径需要项目名)

请求转发(发送了一次请求)

两个或者多个Servlet共享同一份数据的方式

  • 第一种: 将数据放到ServletContext应用域当中,这种方式由于应用域范围太大占用资源太多不建议使用
  • 第二种请求转发机制(一次请求): 将数据放到request域当中,然后在AServlet中转发到BServlet保证AServlet和BServlet在同一次请求当中

在浏览器地址栏上发送的请求是http://localhost:8080/servlet10/a ,最终请求结束之后浏览器地址栏上的地址还是这个

  • A转发到B再转发到C,不管转发了多少次都在同一个request当中,因为调用forward方法的时候会将当前的request和response对象传递给下一个Servlet
  • 转发是服务器根据请求路径自己完成内部资源的跳转,转发路径以“/”开始且不加添加项目名 , 跳转动作是Tomcat服务器内部完成的
    在这里插入图片描述

把AServlet和BServlet放到一次请求当中, 即执行了AServlet之后立马跳转到BServlet保证两个Servlet在同一次请求当中

  • 先获取请求转发器对象(包含下一个要跳转资源的路径), 然后调用请求转发器RequestDispatcher的forward方法进行转发(携带request和response参数)
// AServelt向请求域中存储数据并转发到BSevlet
public class AServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取系统当前时间
        Date nowTime = new Date();
        // 将系统当前时间绑定到请求域当中
        request.setAttribute("sysTime", nowTime);
        // 第一步:先获取请求转发器对象,把"/b"这个路径包装到请求转发器当中,实际上是把下一个跳转的资源的路径告知给Tomcat服务器
        //RequestDispatcher dispatcher = request.getRequestDispatcher("/b");
        // 第二步:调用请求转发器RequestDispatcher的forward方法进行转发,转发的时候request和response都是要传递给下一个资源的
        //dispatcher.forward(request, response);

        // 转发到一个Servlet
        request.getRequestDispatcher("/b").forward(request, response);
        // 转发到一个HTML
        // request.getRequestDispatcher("/test.html").forward(request, response);
    }
}

// BSevlet中取出AServelt中向请求域中绑定的数据 
public class BServlet extends HttpServlet{
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException,ServletException{
		// 可以从request域当中取出绑定的数据
		Object obj = request.getAttribute("sysTime");
        // 输出到浏览器
        response.setContentType("text/html;charset=UTF-8");
		PrintWriter out = response.getWriter();
		out.print("request域当中获取的系统当前时间 = " + obj);
	}
}

响应重定向(发送了多次请求)

在浏览器地址栏上发送的请求是http://localhost:8080/servlet10/a ,最终在浏览器地址栏上显示的地址是http://localhost:8080/servlet10/b

  • response对象将重定向到的请求路径响应给浏览器 , 浏览器会根据服务器响应的请求路径在地址栏上重新发起一个get请求(重定向路径需要添加项目名)
  • 由于重定向是多次请求所以不能共享请求域中的数据,需要使用其他域如会话域/应用域实现资源共享

在这里插入图片描述

AServlet向请求域中存储数据,在BServlet拿不到AServlet向请求域中存储的数据,因为这是两个不同的请求即不在同一个请求域当中

  • 浏览器一共发送了两次请求:最终浏览器地址栏上显示的地址当然是最后那一次请求的地址,所以重定向会导致浏览器地址栏上的地址发生改变
// AServelt向请求域中存储数据并重定向到BSevlet
public class AServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取系统当前时间
        Date nowTime = new Date();
        // 将系统当前时间绑定到请求域当中
        request.setAttribute("sysTime", nowTime);
        // response对象将请求路径"/servlet/b"响应给浏览器了,浏览器又自发的向服务器发送了一次全新的请求
        // 第一次请求:http://localhost:8080/servlet/a ---> 第二次请求:http://localhost:8080/servlet/b
        response.sendRedirect(request.getContextPath() + "/b");
    }
}

// BSevlet中无法取出AServelt中向请求域中绑定的数据 
public class BServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 从请求域当中取不到存储的数据,取出的是null
		Object obj = request.getAttribute("sysTime");   
        
        // 输出到浏览器
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
		out.print("request域当中获取的系统当前时间 = " + obj);
    }
} 

转发存在浏览器的刷新问题

当使用转发跳转到success.html页面并刷新当前页面时 , 页面刷新一次数据库中会插入一次数据 , 因为地址栏上的请求还是之前的那个请求没变

当使用重定向跳转到success.html页面并刷新当前页面时 , 无论如何刷新数据库中都不会插入数据 , 因为地址栏上的请求变成了最后一次的请求

创建t_student学生表

create table t_student(
    no int,
    name varchar(255),
);

准备Student.html表单页面发起get请求

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>学生</title>
    </head>
    <body>
        <form action="/student/save" method="get">
            学生编号<input type="text" name="no"><br>
            学生姓名<input type="text" name="name"><br>
            <input type="submit" value="保存">
        </form>
    </body>
</html>

编写StudentSaveServlet处理请求保存学生的信息到数据库(配置到web.xml文件中)

 <servlet>
        <servlet-name>student</servlet-name>
        <servlet-class>com.yunqing.oa.test.StudentSaveServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>student</servlet-name>
        <url-pattern>/student/save</url-pattern>
    </servlet-mapping>
public class StudentSaveServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 保存学生信息到数据库
        request.setCharacterEncoding("UTF-8");
        String no = request.getParameter("no");
        String name = request.getParameter("name");
        Connection conn = null;
        PreparedStatement ps = null;
        int count = 0;
        try {
            conn = DBUtil.getConnection();
            String sql = "insert into t_student(no,name) values(?,?)";
            ps = conn.prepareStatement(sql);
            ps.setString(1, no);
            ps.setString(2, name);
            count = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(conn, ps, null);
        }
        // 保存成功之后跳转到成功页面
        if (count == 1) {
            // 转发: 页面刷新一次数据库中会插入一次数据
            //request.getRequestDispatcher("/success.html").forward(request, response);
            // 重定向: 无论如何刷新数据库中都不会插入数据
            response.sendRedirect(request.getContextPath() + "/success.html");
        }else{

        }       
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/672219.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Python】Django 基础知识

系列文章目录 提示&#xff1a;阅读本章之前&#xff0c;请先阅读目录 文章目录 系列文章目录前言安装启动项目查看所有子命令主要文件setting 配置项URL 请求路径path 转换器HttpResponse 输出中文乱码models的objects代码自动补全views的request 代码自动补全views的request.…

沃尔玛、亚马逊跨境电商如何实现自养账号采退、海淘及测评的

今天曹哥还是针对下亚马逊、沃尔玛跨境平台如何实现自己养买家号可以给自己采购、海淘及测评等技术问题 首先你要有一个稳定的环境方案&#xff0c;这个是做自养号采购、海淘及测评的基础。环境有很多&#xff0c;从早期的虚拟机&#xff0c;模拟机&#xff0c;云手机&#xf…

[进阶]Java:IO流分类、文件字节输入流、读取字节数据、避免乱码问题

IO流概述 I表示intput&#xff0c;是数据从硬盘文件读入到内存的过程&#xff0c;称之输入&#xff0c;负责读。O表示output&#xff0c;是内存程序的数据从内存到写出到硬盘文件的过程&#xff0c;称之输出&#xff0c;负责写。 IO流的分类 按流的方向分 按流中的数据最小单…

树状数组(入门附模板)

声明&#xff1a;本篇文章图片非原创 目录 简介 lowbit函数 结构分析 单点修改,区间查询 区间修改,单点查询 区间修改,区间查询 模板题 树状数组1–单点修改,区间查询 题目描述 输入格式 输出格式 输入输出样例 输入 #1 输出 #1 说明/提示 分析 代码 树状数…

移动机器人路径优化:基于Q-learning算法的移动机器人路径优化(提供MATLAB代码)

一、Q-learning算法 Q-learning算法是强化学习算法中的一种&#xff0c;该算法主要包含&#xff1a;Agent、状态、动作、环境、回报和惩罚。Q-learning算法通过机器人与环境不断地交换信息&#xff0c;来实现自我学习。Q-learning算法中的Q表是机器人与环境交互后的结果&#…

哈工大计算机网络课程网络层协议详解之:CIDR与路由聚集

哈工大计算机网络课程网络层协议详解之&#xff1a;CIDR与路由聚集 文章目录 哈工大计算机网络课程网络层协议详解之&#xff1a;CIDR与路由聚集CIDR与路由聚集CIDR路由聚集 CIDR与路由聚集 CIDR CIDR&#xff1a;无类域间路由&#xff08;CIDR&#xff1a;Classless InterDo…

2.4C++派生类的函数

C 派生类的构造函数 在C中派生类的构造函数&#xff0c;必须调用基类的构造函数&#xff0c;来初始化从基类继承的数据成员。 具体有两种形式&#xff1a; 1、默认构造函数 2、带参数的构造函数 上面的我写的代码中&#xff0c;DerivedClass 构造函数的初始化列表中调用了 …

前缀和以及map混用,打开思路

补一个坑 目录 以力扣560为例&#xff1a; 力扣1248&#xff0c;优美子数组 力扣974 和可被 K 整除的子数组 力扣523.连续的子数组和 浅谈一下前缀和&#xff1a; 我们通过前缀和数组保存前 n 位的和&#xff0c;presum[1]保存的就是 nums 数组中前 1 位的和&#xff0c;也…

王道考研数据结构--3.双链表

目录 1.前言 2.代码难点 2.1双链表的插入和删除 3.代码函数 3.1双链表结构体定义 3.2双链表初始化函数 3.3双链表插入 3.4双链表节点删除 3.5双链表的遍历 4.全部代码 1.前言 日期&#xff1a;2023.6.21 书籍&#xff1a;2024年数据结构考研复习指导&#xff08;王道…

【计算机视觉】CVPR 23 | 视觉 Transformer 全新学习范式!用长尾数据提升ViT性能

文章目录 一、导读二、介绍三、方法四、总结 一、导读 论文地址&#xff1a; https://arxiv.org/abs/2212.02015代码链接&#xff1a; https://github.com/XuZhengzhuo/LiVT二、介绍 在机器学习领域中&#xff0c;学习不平衡的标注数据一直是一个常见而具有挑战性的任务。近…

JDK自带的构建线程池的方式之newScheduleThreadPool

顾名思义newScheduleThreadPool是一个定时任务的线程池&#xff0c;这个线程池可以定时一定周期去执行任务&#xff0c;也可以实现延迟多久去执行任务一次。 newScheduleThreadPool方法实现展示 基于查看这个方法不难发现&#xff0c;该方法是基于ScheduledThreadPoolExecutor…

基于 Flink CDC 构建 MySQL 到 Databend 的 实时数据同步

这篇教程将展示如何基于 Flink CDC 快速构建 MySQL 到 Databend 的实时数据同步。本教程的演示都将在 Flink SQL CLI 中进行&#xff0c;只涉及 SQL&#xff0c;无需一行 Java/Scala 代码&#xff0c;也无需安装 IDE。 假设我们有电子商务业务&#xff0c;商品的数据存储在 My…

【深度学习】5-5 与学习相关的技巧 - 超参数的验证

超参数指的是&#xff0c;比如各层的神经元数量、batch大小、参数更新时的学习率或权值衰减等。如果这些超参数没有设置合适的值&#xff0c;模型的性能就会很差。 那么如何能够高效地寻找超参数的值的方法 验证数据 之前我们使用的数据集分成了训练数据和测试数据&#xff0c…

WorkPlus AI助理正式上线!为企业打造定制化的AI私有助理

毋庸置疑&#xff0c;ChatGPT的应用充满无限的想象空间。但对于企业来说&#xff0c;使用时面临的最核心的问题就是“存在回答准确性不足”的弊端。那企业都想要通过GPT构建内容生态&#xff0c;在数字化时代保持行业领先地位。 企业都想要结合行业属性、业务需求等自身特点打…

【Flutter】Flutter 数据存储 Hive 的简要使用说明

文章目录 一、前言二、Hive 包的版本号三、Hive 简介1. Hive 是什么&#xff1f;2. Hive 的特点 四、Hive 的基本使用1. Hive 的安装2. Hive 的初始化3. 创建和打开 Hive 数据库4. 数据的存储和读取5. 数据的删除 五、总结 一、前言 &#x1f389;想要精通 Flutter&#xff0c…

是时候扔掉cmder, 换上Windows Terminal

作为一个Windows的长期用户&#xff0c;一直没有给款好用的终端&#xff0c;知道遇到了 cmder&#xff0c;它拯救一个习惯用Windows敲shell命令的人。 不用跟我安利macOS真香&#xff01;公司上班一直用macOS&#xff0c;一方面确实更加习惯windows下面学习, 另一方面是上课需要…

Phantomjs实现后端将URL转换为图片

PhantomJS简介 PhantomJS is a command-line tool. – 其实就是一个命令行工具 PhantomJS的下载地址&#xff1a; Windows:phantomjs-2.1.1-windows.zip Linux:phantomjs-2.1.1-linux-x86_64.tar.bz2;phantomjs-2.1.1-linux-i686.tar.bz2 MacOS:phantomjs-2.1.1-macosx.zip…

西门子Mendix 入门 2

今天还是一直下载失败&#xff0c;就算成功了&#xff0c;速度也只有几K&#xff0c;于是使用翻墙软件&#xff0c;最终下载成功 下载成功后重新点击edit in studio pro 出现如下页面 首先先关闭安全性 进行添加任务和管理任务 点击上方绿色箭头后点击View App 出现如下页面…

ESP32-WROOM-32 UDP单播透传AT指令例程

ESP32-WROOM-32 AT指令配置TCP通讯 ESP32-WROOM-32前言固件烧录测试AT指令UDP单播通讯\透传ESP32配置SoftAPESP32与手机间的UDP通讯与透传普通传输模式演示UDP透传演示 ESP32-WROOM-32 前言 上次演示了ESP32与手机的三种TCP连接与数据传输方法&#xff0c;现在接着上一篇“ESP…

第二章 数据结构(一)——链表,栈和队列与kmp

文章目录 链表栈和队列表达式运算 单调栈单调队列kmp链表练习题826. 单链表827. 双链表 栈和队列练习题828. 模拟栈3302. 表达式求值829. 模拟队列830. 单调栈154. 滑动窗口 kmp练习题831. KMP字符串 kmp虐我一下午 链表 若用链式结构实现链表&#xff0c;效率低&#xff0c;因…