HttpServletRequest & HttpServletResponse

本文深入解析了HTTP请求与响应的全过程,涵盖了HttpServletRequest与HttpServletResponse的主要功能,包括获取客户端信息、请求参数、URL及响应状态码、响应头、响应体等关键细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HttpServletRequest

封装了客户端所有的请求数据
请求协议中的数据都可以通过request对象来获取!

  * 获取常用信息
    > request.getRemoteAddr()获取客户端IP
    > request.getMethod()获取请求方式,POST或者GET
    
  * 获取HTTP请求头
    > String getHeader(String name),适用于单值头
    > int getIntHeader(String name),适用于单值int类型的请求头
    > long getDateHeader(String name),适用于单值毫秒类型的请求头
    > Enumeration<String> getHeaders(String name),适用于多值请求头
    
  * 获取请求URL
	 http://localhost:8080/servletdemo/AServlet?username=xxx&password=yyy
    > String getScheme():获取协议,http
    > String getServerName():获取服务器名,localhost
    > String getServerPort():获取服务器端口,8080
    > String getContextPath():获取项目名,/servletdemo
    > String getServletPath():获取Servlet路径,/AServlet
    > String getQueryString():获取参数部分,即问号后面的部分。username=xxx&password=yyy
    > String getRequestURI():获取请求URI,等于项目名+Servlet路径。/servletdemo/AServlet
    > String getRequestURL():获取请求URL,等于不包含参数的整个请求路径。http://localhost:8080/servletdemo/AServlet
    
  * 获取请求参数:
  请求参数是由客户端发送给服务器的!有可能是在请求体中(POST),也可能是在URL之后(GET)
  请求参数:有一个参数一个值的,还有一个参数多个值!
    > String getParameter(String name):获取指定名称的请求参数值,适用于单值请求参数
    > String[] getParameterValues(String name):获取指定名称的请求参数值,适用于多值请求参数
    > Enumeration<String> getParameterNames():获取所有请求参数名称
    > Map<String,String[]> getParameterMap():获取所有请求参数,其中key为参数名,value为参数值。
    
  * 请求转发和请求包含
  RequestDispatcher rd = request.getRequestDispatcher("/MyServlet");  使用request获取RequestDispatcher对象,方法的参数是被转发或包含的Servlet的Servlet路径
  请求转发:rd.forward(request,response);
  请求包含:rd.include(request,response);
  有时一个请求需要多个Servlet协作才能完成,所以需要在一个Servlet跳到另一个Servlet!
    > 一个请求跨多个Servlet,需要使用转发和包含。
    > 请求转发:由下一个Servlet完成响应体!当前Servlet可以设置响应头!
    > 请求包含:由两个Servlet共同未完成响应体!
    > 无论是请求转发还是请求包含,都在一个请求范围内!使用同一个request和response!

  * 请求转发和重定向的区别
    > 请求转发是一个请求一次响应,而重定向是两次请求两次响应
    > 请求转发地址栏不变化,而重定向会显示后一个请求的地址
    > 请求转发只能转发到本项目其他Servlet,而重定向不只能重定向到本项目的其他Servlet,还能定向到其他项目
    > 请求转发是服务器端行为,只需给出转发的Servlet路径,而重定向需要给出requestURI,即包含项目名!
    > 请求转发和重定向效率是转发高!因为是一个请求!
	    -- 需要地址栏发生变化,那么必须使用重定向!
        -- 需要在下一个Servlet中获取request域中的数据,必须要使用转发!
        -- 重定向需要 ***response***对象设置sendRedirect(String location)
        
  * request域
  JavaWeb中三大域对象:page、request、session、application,都有如下三个方法:
    > void setAttribute(String name, Object value)
    > Object getAttribute(String name)
    > void removeAttribute(String name);
    > 同一请求范围内(请求转发或包含)使用request.setAttribute()、request.getAttribute()来传值!前一个Servlet调用setAttribute()保存值,后一个Servlet调用getAttribute()获取值。

HttpServletResponse

封装http协议中响应的内容

  * 状态码:
  200表示成功、302表示重定向、404表示客户端错(访问的资源不存在)、500表示服务器端错
    > sendError(int sc) --> 发送错误状态码,例如404、500
    > sendError(int sc, String msg) --> 也是发送错误状态码,还可以带一个错误信息!
    > setStatus(int sc) --> 发送成功的状态码,可以用来发送302
    
  * 响应头:
  Content-Type、Refresh、Location等等
  头就是一个键值对!可能会存在一个头(一个名称,一个值),也可能会存在另一种头(一个名称,多个值!)
    > setHeader(String name, String value):适用于单值的响应头,例如:response.setHeader("aaa", "AAA");
    > addHeader(String name, String value):适用于多值的响应头
       -- response.addHeader("aaa", "A");
       -- response.addHeader("aaa", "AA");
       -- response.addHeader("aaa", "AAA");
    > setIntHeader(String name, int value):适用于单值的int类型的响应头
       -- response.setIntHeader("Content-Length", 888);
    > addIntHeader(String name, int value):适用于多值的int类型的响应头
    > setDateHeader(String name, long value):适用于单值的毫秒类型的响应头
       -- response.setDateHeader("expires", 1000 * 60 * 60 * 24);
    > addDateHeader(String name, long value):适用于多值的毫秒类型的响应头

  * 响应体:通常是html、也可以是图片!
    > response的两个流:
       -- ServletOutputStream,用来向客户端发送字节数据。ServletOutputStream out = resopnse.getOutputStream();
       --  PrintWriter,用来向客户端发送字符数据!需要设置编码。PrintWriter writer = response.getWriter();
       --  注意:两个流不能同时使用!

  * 重定向:
  设置302,设置Location!其中变化的只有Location,所以java提供了一个快捷方法,完成重定向!
    > sendRedirect(String location)方法

常用编码

常见字符编码:iso-8859-1(不支持中文)、gb2312、gbk、gb18030(系统默认编码,中国的国标码)、utf-8(万国码,支持全世界的编码,所以我们使用这个)

1. 响应编码

  * 当使用response.getWriter()来向客户端发送字符数据时,如果在之前没有设置编码,那么默认使用iso,因为iso不支持中文,一定乱码
  * 在使用response.getWriter()之前可以使用response.setCharaceterEncoding()来设置字符流的编码为gbk或utf-8,当然我们通常会选择utf-8。这样使用response.getWriter()发送的字符就是使用utf-8编码的。但还是会出现乱码!因为浏览器并不知道服务器发送过来的是什么编码的数据!这时浏览器会使用gbk来解码,所以乱码!
  * 在使用response.getWriter()之前可以使用response.setHeader("Content-type","text/html;charset=utf-8")来设置响应头,通知浏览器服务器这边使用的是utf-8编码,而且在调用setHeader()后,还会自动执行setCharacterEncding()方法。这样浏览器会使用utf-8解码,所以就不会乱码了!
  * setHeader("Content-Type", "text/html;charset=utf-8")的快捷方法是:setContentType("text/html;charset=utf-8)。

2. 请求编码

  * 客户端发送给服务器的请求参数是什么编码:
  客户端首先要打开一个页面,然后在页面中提交表单或点击超链接!在请求这个页面时,服务器响应的编码是什么,那么客户端发送请求时的编码就是什么。
  * 服务器端默认使用什么编码来解码参数:
  服务器端默认使用ISO-8859-1来解码!所以这一定会出现乱码的!因为iso不支持中文!
  * 请求编码处理分为两种:GET和POST:GET请求参数不在请求体中,而POST请求参数在请求体中,所以它们的处理方式是不同的!
  * GET请求编码处理:
    > String username = new String(request.getParameter("paramName").getBytes("iso-8859-1"), "utf-8");
    > 在server.xml中配置URIEncoding=utf-8
  * POST请求编码处理:
    > 在获取参数之前调用request.setCharacterEncoding("utf-8");

3. URL编码
表单的类型:Content-Type: application/x-www-form-urlencoded,就是把中文转换成%后面跟随两位的16进制。
为什么要用它:在客户端和服务器之间传递中文时需要把它转换成网络适合的方式。

  * 它不是字符编码!
  * 它是用来在客户端与服务器之间传递参数用的一种方式!
  * URL编码需要先指定一种字符编码,把字符串解码后,得到byte[],然后把小于0的字节+256,再转换成16进制。前面再添加一个%。
  * POST请求默认就使用URL编码!tomcat会自动使用URL解码!
  * URL编码:String username = URLEncoder.encode(username, "utf-8");
  * URL解码:String username = URLDecoder.decode(username, "utf-8");

4. unicode
概念:
它为每种语言中的每个字符设定了统一并且唯一的二进制编码
BMP:
基本多文种平面(Basic Multilingual Plane),它又简称为“零号平面”, plane 0

方式:
	Unicode字符分为17组编排,每组称为平面(Plane),而每平面拥有65536个码位,
16进制范围从0x0000 至 0xFFFF,共1114112个=65536*17。
    1991年前后,国际标准化组织(ISO)和统一码联盟开始合并双方的工作成果,并为
创立一个单一编码表而协同工作。从Unicode 2.0开始,Unicode采用了与ISO 10646-1
相同的字库和字码;ISO也承诺,ISO 10646将不会替超出U+10FFFF(1114112)的UCS-4
编码赋值,以使得两者保持一致。
    UCS-4(ISO标准)根据最高位为0的最高字节分(0x7F)成2^7=128个group。每个group再根据次高字节(0xFF)
分为256个平面(plane)。每个平面根据第3个字节(0xFF)分为256行 (row),每行有256个码位(cell)。
0x00 00 00 00 ~ 0x7F FF FF FF
group 0的平面0被称作BMP(Basic Multilingual Plane)。如果UCS-4的前两个字节为全零,那
么将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。每个平面有2^16=65536个码位。Unicode
计划使用了17个平面,一共有17×65536=1114112个码位。在Unicode 5.0.0版本中,已定义的码
位只有238605个,分布在平面0、平面1、平面2、平面14、平面15、平面16。其中平面15和平面16
上只是定义了两个各占65534个码位的专用区(Private Use Area),分别是0xF0000-0xFFFFD和
0x100000-0x10FFFD。所谓专用区,就是保留给大家放****自定义字符****的区域,可以简写为PUA。

注:65534=0~0xFFFD个 15=0xF 16=0x10

平面0也有一个专用区:0xE000-0xF8FF,有6400个码位。平面0的0xD800-0xDFFF,共2048个码位,
是一个被称作代理区(Surrogate)的特殊区域。代理区的目的用两个UTF-16字符表示BMP以外的
字符。在介绍UTF-16编码时会介绍。

注:6400=0~0x18FF=0xF8FF-0xE000 2048=0~7FF=0xDFFF-0xD800

如前所述在Unicode 5.0.0版本中,238605-65534*2(自定义字符区)-6400(专用区)-2048(代理区)=99089。
余下的99089个已定义码位分布在平面0、平面1、平面2和平面14上,它们对应着Unicode定义的
99089个字符,其中包括71226个汉字。平面0、平面1、平面2和平面14上分别定义了52080、3419、
43253和337个字符。平面2的43253个字符都是汉字。平面0上定义了27973个汉字。

注:已定义的字符99089=52080(plane0包含27973个汉字)+3419(plane1)+43253(plane2全是汉字)+337(plane14)
    汉字个数99089=27973+43253
    65版新华字典8500汉字,2004(10版)11200个汉字,也就是说字典里的汉字完全可以放在plane0中,
    但实际情况怎么样没有考证。

5. UTF-8
UTF-8以字节为单位对Unicode进行编码。从Unicode到UTF-8的编码方式如下:

Unicode编码(十六进制)	UTF-8 字节流(二进制)
000000-00007F		0xxxxxxx
000080-0007FF		110xxxxx 10xxxxxx
000800-00FFFF		1110xxxx 10xxxxxx 10xxxxxx
010000-1FFFFF		11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
...
00000000-7FFFFFFF	1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

UTF-8的特点是对不同范围的字符使用不同长度的编码。对于0x00-0x7F之间的字符,UTF-8编码与
ASCII编码完全相同。UTF-8编码的最大长度是6个字节。从上表可以看出,6字节模板有31个x,即
可以容纳31位二进制数字。Unicode的最大码位0x7FFFFFFF也只有31位(可也理解为UCS-4标准)。
实际上使用范围0x000000-0x10FFFF。

例1:“汉”字的Unicode编码是0x6C49。0x6C49在0x0800-0xFFFF之间,使用用3字节模板了:
1110xxxx 10xxxxxx 10xxxxxx。将0x6C49写成二进制是:0110 1100 0100 1001, 用这个比特流	
依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。

例2:Unicode编码0x20C30在0x010000-0x1FFFFF之间,使用用4字节模板了:11110xxx 10xxxxxx
 10xxxxxx 10xxxxxx。将0x20C30写成21位二进制数字(不足21位就在前面补0):0 0010 0000 
1100 0011 0000,用这个比特流依次代替模板中的x,得到:11110000 10100000 10110000 1011
0000,即F0 A0 B0 B0。

6. UTF-16
如果U<0x10000,U的UTF-16编码就是U对应的16位无符号整数(为书写简便,下文将16位无符号整
数记作WORD)。

如果U≥0x10000,我们先计算U'=U-0x10000,然后将U'写成二进制形式:yyyy yyyy yyxx xxxx xxxx,
U的UTF-16编码(二进制)就是:1101 10yy yyyy yyyy 1101 11xx xxxx xxxx。
为什么U'可以被写成20个二进制位?Unicode的最大码位是0x10ffff,减去0x10000后,U'的最大值是0xfffff,
所以肯定可以用20个二进制位表示。

D800-DB7F	High Surrogates			高位替代
DB80-DBFF	High Private Use Surrogates	高位专用替代
DC00-DFFF	Low Surrogates			低位替代

UTF-16编码的第一个WORD在0xdb80到0xdbff之间,换算为Unicode编码范围0xf0000-0x10ffff,
即平面15和平面16(专用区(Private Use Area))

7. char

utf-16编码,即BMP

8. String

utf-16编码
增补字符,占两个位置但是算一个索引。

常见路径书写

  * 转发和包含路径
    > 以“/”开头:相对当前项目路径,例如:http://localhost:8080/项目名/ request.getRequestdispacher("/BServlet").forward();
    > 不以“/”开头:相对当前Servlet路径。 request.getRequestdispacher("BServlet").forward();,假如当前Servlet是:http://localhost:8080/项目名/servlet/AServlet, 结果就是http://localhost:8080/项目名/servlet/BServlet
  * 重定向路径(客户端路径)
    > 以“/”开头:相对当前主机,例如:http://localhost:8080/, 所以需要自己手动添加项目名,例如;response.sendRedirect("/servletdemo/Bservlet");
  * 页面中超链接和表单路径
    > 与重定向相同,都是客户端路径!需要添加项目名
    > <form action="/servletdemo/AServlet">
    > <a href="/servletdemo/AServlet">
    > <a href="AServlet">,如果不以“/”开头,那么相对当前页面所在路径。如果是http://localhost:8080/servletdemo/html/form.html。 即:http://localhost:8080/servletdemo/html/ASevlet
    > 建议使用以“/”开头的路径,即绝对路径!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值