java web请求_Java Web请求和响应机制

请求响应流程图

2dcc173441b11b441618c1bf5d011ab0.png

===================

服务器处理请求的流程:

服务器每次收到请求时,都会为这个请求开辟一个新的线程。

服务器会把客户端的请求数据封装到request对象中,request就是请求数据的载体!

服务器还会创建response对象,这个对象与客户端连接在一起,它可以用来向客户端发送响应。

===================

response:其类型为HttpServletResponse

*状态码:200表示成功、302表示重定向、404表示客户端错误(访问的资源不存在)、500表示服务器错误

>sendError(int sc):发送错误的状态码,例如404、500

>sendError(int sc, String msg):发送错误的状态码+错误信息

>sendStatus(int sc):发送成功的状态码,例如302

404案例:

1 //404案例

2 @Override3 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {4 resp.sendError(404,"您访问的资源不存在!!!");5 }

*响应头:Content-Type、Refresh、Location等等

头就是一个键值对!可能会存在一个头(一个名称,一个值),也可能会存在一个头(一个名称,多个值!)

>(重要)setHeader(String name, String value):适用于单值的响应头,例如:response.setHeader("aa","AAA");

>addHeader(String name, String value):适用于多值的响应头

response.addHeader("aa","A");

response.addHeader("aa","AA");

response.addHeader("aa","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);  设置页面过期时间为24小时

>addDateHeader(String name, long value):适用于多值的毫秒类型的响应头

案例:

1)发送302,设置Location头,完成重定向!

bdd306c26b20f986481557d0e89670c3.png

BServlet

1 //重定向1.设置Location头(重定向的地址)2.响应302状态码

2

3 @WebServlet("/BServlet")4 public class BServlet extendsHttpServlet {5 //重定向1.设置Location 2.发送302状态码

6

7 @Override8 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {9 System.out.println("BServlet");10 //请求URI s1的值:/项目名/Servlet名

11 resp.setHeader("Location","/CServlet");12 resp.setStatus(302);13 }14 }

CServlet

1 @WebServlet("/CServlet")2 public class CServlet extendsHttpServlet {3 @Override4 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {5 System.out.println("CServlet");6 }7 }

2)定时刷新:设置Refresh头(你可以把它理解成,定时重定向!)

DServlet

1 @WebServlet("/DServlet")2 public class DServlet extendsHttpServlet {3 @Override4 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {5 System.out.println("DServlet");6 resp.setHeader("Refresh","5;URL=/CServlet");//5秒后重定向到Cservlet7 }8 }

3)禁用浏览器缓存:Cache-Control、pragma、expires

FServlet

1 @WebServlet("/FServlet")2 public class FServlet extendsHttpServlet{3 @Override4 protected voiddoGet(HttpServletRequest request, HttpServletResponse response){5 response.setHeader("Cache-Control","no-cache");6 response.setHeader("pragma","no-cache");7 response.setDateHeader("expires",-1);//过期时间为-1,也就是不缓存

8 }9 }

在index.jsp中有

51a2510ccfcde082010e011abb1732c4.png

4)标签可以替代响应头:

*响应体: 通常是html、也可以是图片!

>response的两个流:

<>ServletOutputStream,用来向客户端发送字节数据。ServletOutputStream out=response.getOutputStream();

<>PrintWriter,用来向客户端发送字符数据!需要设置编码。PrintWriter pw=response.getWriter();

<>两个流不能同时使用!

在Interface ServletResponse接口中有方法getOutputStream()和getWriter(),如果同时使用,会抛出

案例:(不同时)使用两个流

1)使用ServletOutputStream字节流向客户端写字符串和图片

1 @WebServlet("/GServlet")2 public class GServlet extendsHttpServlet {3 @Override4 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {5 /*String s="Hello outputStream 谢";6 byte[] bytes=s.getBytes();//将字符串转换成字节,存储到byte数组中7 resp.getOutputStream().write(bytes);//字节流*/

8

9 //响应字节数据,1.把一张图片读取到字节数组中2.使用字节流进行输出

10 FileInputStream in=new FileInputStream("G://金软软.jpg");11 //读取输入流内容的字节到字节数组中

12 byte[] bytes1=IOUtils.toByteArray(in);13 resp.getOutputStream().write(bytes1);14 }15 }

2)使用PrintWriter字符流向客户端写内容,需要设置字符编码

1 @WebServlet("/HServlet")2 public class HServlet extendsHttpServlet {3 @Override4 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {5 resp.setContentType("text/html;charset=utf-8");6 resp.getWriter().write("谢军帅");7 resp.getWriter().print("
金泰妍");8 }9 }

*重定向:设置302,设置Location!其中变化的只有Location,所以Java提供了一个快捷方法,完成重定向1

>sendRedirect(String location)方法

1 //快捷

2 resp.sendRedirect("http://www.baidu.com");

request:封装了客户端所有的请求数据!

请求行

请求头

空行

请求体(GET没体)

*获取常用信息

>获取客户端IP,request.getRemoteAddr()

>请求方式,request.getMethod(),可能时POST或GET

*获取请求头

>(重要)String getHeader(String name),适用于单值头

>int getInHeader(String name),适用于单指int类型的请求头

>long getDateHeader(String name),适用于单值毫秒类型的请求头

>Enumeration getHeaders(String name),适用于多值请求头

通过User-Agent识别用户浏览器类型

1 //演示:获取客户端的IP地址、获取请求方式、获取User-Agent,得到客户端的信息(操作系统,浏览器)

2 @WebServlet("/Servlet2")3 public class Servlet2 extendsHttpServlet {4 @Override5 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {6 String remoteAddr =req.getRemoteAddr();7 System.out.println("(IPV6)IP:"+remoteAddr);8 String method =req.getMethod();9 System.out.println("请求方式:"+method);10 String userAgent = req.getHeader("User-Agent");11 System.out.println("userAgent:"+userAgent);12 //先把字符串转换成小写,,然后再看是否包含

13 if(userAgent.toLowerCase().contains("chrome")){14 System.out.println("您好"+remoteAddr+"您使用的是谷歌浏览器");15 }else if (userAgent.toLowerCase().contains("firefox")){16 System.out.println("您好"+remoteAddr+"您使用的是火狐浏览器");17 }else if (userAgent.toLowerCase().contains("msie")){18 System.out.println("您好"+remoteAddr+"您使用的时IE浏览器");19 }else{20 System.out.println("不晓得你用的啥");21 }22 }23 }

防盗链:如果请求不是通过本站的超链接发出的,发送错误状态码404。Refresh这个请求头,表示请求的来源!(比如:从一个页面跳转到另一个页面,都会有Refresh值)

1 @WebServlet("/Servlet3")2 public class Servlet3 extendsHttpServlet {3 @Override4 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throwsIOException {5 /*使用Refresh请求头,来防盗链*/

6 String referer = req.getHeader("Referer");7 System.out.println(referer);8 if(referer == null || !referer.contains("localhost")){//如果前面的满足的话,后边的就不用判断了

9 resp.sendRedirect("http://www.baidu.com");10 }else{11 System.out.println("hello");12 }13 }14 }15 /*

16 Referer这个头可以得到请求的来源;17 1.在地址栏中请求的话其值为null18 2.在其它页面以链接的形式请求的话其值为URL19 */

*获取请求URL

http://localhost:8080/day10_2/AServlet?username=xxx&password=yyy

>String getScheme():获取协议,http

>String getServerName():获取服务器名,localhost

>String getServerPort():获取服务器端口,8080

>String getContextPath():获取项目名(会经常使用,重要),/day10_2

>String getServletPath():获取Servlet路径,/AServlet

>String getQueryString():获取参数部分,即问号后面的部分,username=xxx&password=yyy

>String getRequestURI():获取请求URI,等于项目名+Servlet路径,/day10_2/AServlet

>String getRequestURL():获取请求URL,等于不包括参数的整个请求路径,http://localhost:8080/day10_2/AServlet

*获取请求参数:请求参数是由客户端发送给服务器的!有可能是在请求体中(POST),也可能在URL之后(GET)

>***String getParameter(String name):获取指定名称的请求参数值,适用于单值请求参数

>String[]  getParameterValues(String name):获取指定名称的请求参数值,适用于多值请求参数

>Enumeration  getParameterNames():获取所有请求参数的名称

>***Map  getParameterMap():获取所有的请求参数,其中key为参数名,value为参数值。将请求的参数封装到Map中

案例:超链接参数

案例:表单数据

*请求转发和请求包含---dispatcher的英文意思是调度员,来调用别的Servlet

RequestDispatcher rd=request.getRequestDispatcher("/MyServlet");---->使用request获取RequestDispatcher对象,括号里的参数是被转发或包含的Servlet的servlet路径

请求转发:***rd.forward(request,response);

请求包含:rd.include(request,response);

c17061aa4d4121c3b7e2008c8d0c97f2.png

有时一个请求需要多个Servlet协作才能完成,所以需要在一个Servlet跳到另一个Servlet!

>一个请求跨多个Servlet,需要使用转发和包含。

>请求转发:由下一个Servlet完成响应体!当前Servlet可以设置响应头!(留头不留体)

>请求包含:由两个Servlet共同来完成响应体!(都留)

>无论是请求转发还是请求包含,都在一个请求范围内!使用同一个request和response!

请求转发示例:

OneServlet:

1 public class OneServlet extendsHttpServlet {2

3 public voiddoGet(HttpServletRequest request, HttpServletResponse response)4 throwsServletException, IOException {5 System.out.println("OneServlet...");6 response.setHeader("aa", "AA");//头

7 response.getWriter().print("hello OneServlet!");//体8

9 //转发

10 RequestDispatcher rd=request.getRequestDispatcher("/TwoServlet");11 rd.forward(request, response);12 }13 }

TwoServlet:

1 public class TwoServlet extendsHttpServlet {2 public voiddoGet(HttpServletRequest request, HttpServletResponse response)3 throwsServletException, IOException {4 System.out.println("TwoServlet...");5 response.getWriter().print("hello TwoServlet");6 }7 }

在浏览器中访问http://localhost:8080/XJS_Servlet3/OneServlet

控制台结果:

OneServlet...

TwoServlet...

浏览器页面结果:

还有OneServlet设置的头也发送到浏览器了

hello TwoServlet

证明了OneServlet留头不留体

请求包含示例:

Servlet1:

1 public class Servlet1 extendsHttpServlet {2

3 public voiddoGet(HttpServletRequest request, HttpServletResponse response)4 throwsServletException, IOException {5 System.out.println("Servlet1...");6 response.setHeader("aa", "AA");//头

7 response.getWriter().print("hello OneServlet!");//体8

9 //转发

10 RequestDispatcher rd=request.getRequestDispatcher("/include/Servlet2");11 rd.include(request, response);12 }13 }

Servlet2:

1 public class Servlet2 extendsHttpServlet {2

3 public voiddoGet(HttpServletRequest request, HttpServletResponse response)4 throwsServletException, IOException {5 System.out.println("TwoServlet...");6 response.getWriter().print("hello TwoServlet");7 }8

9 }

请求http://localhost:8080/XJS_Servlet3/include/Servlet1的结果:

控制台:

Servlet1...

TwoServlet...

浏览器页面:

hello OneServlet!hello TwoServlet

结果证明:include留头又留体

*request域

Servlet中三大域对象: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()获取值。

*请求转发和重定向的区别

>请求转发是一个请求一次响应,而重定向是两次请求两次响应

>请求转发地址栏不变化,而重定向会显示后一个请求的地址

>请求转发只能转发到本项目的其他Servlet,而重定向不只能重定向到本项目的其他Servlet,还能定向到其他项目

>请求转发是服务器端行为,只需给出转发的Servlet路径,而重定向需要给出requestURL,即包含项目名!!!

>请求转发和重定向效率是转发高!因为是一个请求!

<>需要地址栏发生变化,那么必须使用重定向!

<>需要在下一个Servlet中获取request域中的数据,必须使用转发!

编码

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

1.响应编码

919e3255689de2fe33e3cd957fff4fd2.png

response.setCharacterEncoding("utf-8");//设置服务器的编码为utf-8

response.setHeader("Content-Type","text/html;charset=utf-8");//设置响应头,服务器编码格式为utf-8

response设置Content-Type的快捷方法:

response.setContentType("text/html;charset=utf-8");

想不乱码:在使用getWriter()方法之前,先调用下面方法:

***response.setContentType("text/html;charset=utf-8");

2.请求编码---所有的乱码都有解决的方法(先在Servlet中获取参数,然后在对参数进行反编码)

一般请求参数,在Servlet中获取时不会出现乱码,如果出现乱码就按照下面方法解决乱码:

02858e57771b0eb5138e3dcf40ed23d1.png

*客户端发送给服务器的请求参数是什么编码:

客户端首先要打开一个页面,然后在页面中提交表单或点击超链接!在请求这个页面时,服务器响应的编码是什么,那么客户端发送请求时的编码就是什么

*服务器端默认使用什么编码来解码参数:

(tomcat8之前的)服务器端默认使用ISO-8859-1来解码!所以这一定会出现乱码的!因为iso不支持中文!

在Servlet中设置request.setCharacterEncoding("utf-8");---然后在获取请求参数,可以防止乱码

Tomcat8默认编码为UTF-8

3ef4ddc99e074f83e15f946fe8958006.png

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");

1)GET请求中的中文没有URL编码,可能会出现丢失字节

2)使用的是表单,表单自动使用URL编码

3)服务器会自动识别URL编码,然后自动做URL解码

4.路径

*web.xml中路径,(叫它Servlet路径!)

>要么以 “*” 开头,要么以 “/” 开头。

*转发和包含路径

>以 “/”开头:相对当前项目的路径,例如:http://localhost:8080/项目名/    request.getRequestdispacher("/BServlet").forward(request,response);

>不以 “/” 开头:相对当前Servlet路径

*重定向路径(客户端路径)

>以“ /”开头:相对于当前主机,例如:http://localhost:8080/,所以需要自己手动添加项目名

*页面中超链接和表单路径

>与重定向相同,都是客户端路径!需要添加项目名

>

>

>****建议使用以 “/” 开头的路径,即绝对路径!

*ServletContext获取资源路径

>相对当前项目目录,即index.jsp所在目录。

*ClassLoader获取资源路径

>相对classes目录

>ClassLoader获取资源时,不能以“/”开头!

*Class获取资源路径

>以“/”开头相对classes目录

>不以"/"开头相对当前.class文件所在目录。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值