在前面Http请求的文章中我们看到一个http请求包含请求头,请求体,响应头和响应体,那么对于这些请求方面和响应方面我们与浏览器交互标准是有了,我们后端是不是需要一个关于请求和响应的API,我们为了方便描述一个http请求出现了Request和Response概念。
Request
request这个对象不用事先声明,就可以在JSP网页中使用,在编译为Servlet之后,它会转换为javax.servlet.http.HttpServletRequest形态的对象,HttpServletRequest对象是有关于客户端所发出的请求的对象,只要是有关于客户端请求的信息,都可以由它来取得,例如请求标头、请求方法、请求参数、客户端IP,客户端浏览器等等信息
ServletRequest — 通用request,提供一个request应该具有的最基本的方法.HttpSerletRequest是Rquest的子类针对http协议进行了进一步的增强
Request的操作
获取客户机信息
getRequestURL() 方法返回客户端发出请求完整URL
getRequestURI() 方法返回请求行中的资源名部分
getQueryString() 方法返回请求行中的参数部分
getRemoteAddr() 方法返回发出请求的客户机的IP地址
getMethod() 得到客户机请求方式
getContextPath() 获得当前web应用虚拟目录名称
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//1.获取客户端请求的完整的url
String url=request.getRequestURL().toString();
System.out.println(url);
//2.获取客户端请求的资源的部分名称
String uri=request.getRequestURI();
System.out.println(uri);
//3.获取请求行中的参数部分
String pram=request.getQueryString();
System.out.println(pram);
//4.返回客户端的ip地址(*)
String ip=request.getRemoteAddr();
System.out.println(ip);
//5.获取客户机的请求方式
String method=request.getMethod();
System.out.println(method);
//6.获取当前web的应用的名称
String name=request.getContextPath();
System.out.println(name);
//请求转发时以后有这个方法
response.sendRedirect(request.getContextPath()+"/index.jsp");
}
复制代码
获取请求头信息
获得客户机请求头
getHeader(name)方法 — String
getHeaders(String name)方法 — Enumeration枚举变量 getHeaderNames方法 — Enumeration
获得具体类型客户机请求头
getIntHeader(name)方法 — int
getDateHeader(name)方法 — long(日期对应毫秒)
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//获取客户机的请求头
//String value=request.getHeader("Host");
//System.out.println(value);
//遍历所有的请求头
Enumeration<String> enument=request.getHeaderNames();
while(enument.hasMoreElements()){
String name=enument.nextElement();
String values=request.getHeader(name);
System.out.println(name+":"+values);
}
}
复制代码
获取请求参数
request.getParameter()
浏览器以什么编码来发送请求参数? 浏览器以什么编码打开的表单页面,就用什么编码发送这个页面提交的数据。服务器以什么编码来打开呢?如果不指定,则使用ISO8859-1,这样如果请求参数中有中文必然就乱码了
对于POST提交,可以设置request.setCharacterEncoding(“utf-8”);明确的通知服务器以浏览器发送过来的编码来打开数据就可以解决乱码但是上面的方法只对请求中实体内容部分起作用,所以GET提交的乱码并不能解决. 对于GET提交的乱码,只能手动的进行编解码从而解决乱码问题:
String username = request.getParameter("username");
username = new String(username.getBytes("iso8859-1"),"utf-8");
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
/*
* post提交乱码解决
*/
//此处也要进行对服务器编码进行设置(通知服务器以什么编码解码http请求中的实体内容)
request.setCharacterEncoding("utf-8");
//获取请求参数的值但是传中文字符是会转义到其他的
String name=request.getParameter("username");
//System.out.println(name);
/*
* get提交乱码解决方式(同样也适合post提交方式)
* 现对提交的参数按照iso8859-1进行编码,然后在解码到其他码表转回
*
*/
String username=new String(name.getBytes("iso8859-1"),"utf-8");
/////
//获取到用一个枚举变量的类型;
Enumeration<String> enumeration=request.getParameterNames();
while(enumeration.hasMoreElements()){
String names=enumeration.nextElement();
String values=request.getParameter(names);
System.out.println(names+":"+values);
}
}
复制代码
利用请求域传递对象
`作用范围: 整个请求链上`
`生命周期: 当服务器收到一个请求,创建出代表请求的request对象,request开始.当请求结束,服务器销毁代表请求的request对象,request域结束.`
`作用: 在整个请求链范围内共享数据,通常我们在Servlet中处理好的数据会存入request域后请求转发到jsp页面来进行展示`
复制代码
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//request作用域 全局域 getRequestDispater() 返回一个作为位于给定路径的资源资源的封装器的 RequestDispatcher 对象。
request.setAttribute("banana", "color:yellow");
this.getServletContext().getRequestDispatcher("/Demo2").forward(request, response);
//转发到xxxjsp中
//先要获取其中的数据ru
String result="xxxx";
request.setAttribute("xxx", result);
request.getRequestDispatcher("xxx.jsp");
}
复制代码
实现请求转发和请求包含
(1)请求转发(.forward()):
this.getServletContext().getRequestDispatcher(“”).forward(request,response);
request.getRequestDispatcher(“”).forward(request,response);
`请求转发是希望将请求交给另外一个资源执行,所以应该保证只有最后真正要执行的资源才能够输出数据,所以:`
`请求转发时,如果已经有数据被写入到了response的缓冲区,但是这些数据还没有被发送到客户端,则请求转发时,这些数据将会被清空.但是清空的只是响应中的实体内容部分,头信息并不会被清空.`
`而请求转发时已经有数据被打给了浏览器,那么再进行请求转发,不能成功,会抛出异常,原因是响应已经结束了,再转发交给其他人没意义了`
`在最终输出数据的Servlet执行完成后,response实体内容中的数据将会被设置为已提交的状态,再往里写数据也不会起作用`
复制代码
(2)请求包含(.include()):将两个资源的输出进行合并后输出多个资源同时输出
this.getServletContext().getRequestDispatcher(“”).include(request,response);
request.getRequestDispatcher(“”).include(request,response);
`被包含的Servlet程序不能改变响应消息的状态码和响应头,如果它里面存在这样的语句,这些语句的执行结果将被忽略常被用来进行页面布局`
复制代码
(3)三种资源处理方式的区别
请求重定向
response.sendRedirect();
请求转发
request.getRequestDispatcher().forward();
请求包含
request.getRequestDispatcher().include();
请求重定向和请求转发的区别:
`请求重定向地址栏会发生变化.请求转发地址栏不发生变化.`
`请求重定向两次请求两次响应.请求转发一次请求一次响应.`
`如果需要在资源跳转时利用request域传递域属性则必须使用请求转发 request.getRequestDispatcher().forward();`
`如果希望资源跳转后修改用户的地址栏则使用请求重定向response.sendRedirect();`
`如果使用请求转发也可以重定向也可以,则优先使用请求转发,减少浏览器对服务器的访问次数减轻服务器的压力.`
复制代码
Response
response是Servlet.service方法的一个参数,类型为javax.servlet.http.HttpServletResponse。在客户端发出每个请求时,服务器都会创建一个response对象,并传入给Servlet.service()方法。response对象是用来对客户端进行响应的,这说明在service()方法中使用response对象可以完成对客户端的响应工作。
Response操作
设置编码方式
response.setHeader(“Content-Type”, “text/html;charset=utf-8”);
response.setCharacterEncoding(“utf-8”);
response.getWriter().write(“中国”);
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//这里是一个编码过程,用的是操作系统的编码GBK;
//浏览器打开时也是GBK的打开方式所以没有乱码
//response.getOutputStream().write("English very so easy".getBytes());
//这是会出现乱码,需要让浏览器也使用Utf-8编码打开才不会乱码或则用下面的方法
//response.setHeader("Content-Type", "text/html;charset=utf-8");
//response.getOutputStream().write("中国".getBytes("utf-8"));
/*这时用中文又会乱码这时是只能是服务器把汉字转换为010101然后去查iso8859-1码表
这个码表中没有中文,如果在iso8859-1找不到的话会被转换为?,然而浏览器又会用GBK打开这个编码所以会显示??
这时要指定服务器查的码表
*/
//指定服务器查的码表
response.setCharacterEncoding("gbk");
response.getWriter().write("beijiang");
response.getWriter().write("中国");
//或者这样;
response.setHeader("Content-Type", "text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
response.getWriter().write("中国");
//或者这样;setContentType可以直接指定浏览器和服务器的编码方式
response.setContentType("text/html,charset=utf-8");
response.getWriter().write("中国");
//或者这样SetCharacterEnconding指定服务器的编码
//setContentType指定浏览器的编码
response.setCharacterEncoding("utf-8");
response.setContentType("text/html,charset=utf-8");
response.getWriter().write("中国");
}
复制代码
设置是否缓存(缓存时间)
不进行缓存的设置形式
response.setIntHeader(“Expires”, -1);
response.setHeader(“Cache-control”,”no-cache”);
response.setHeader(“Pragma”,”no-cache”);
设置缓冲并设置缓存的时间
response.setDateHeader(“Expires”, System.currentTimeMillis()+1000L_3600_24*30);
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置缓冲的时间
response.setDateHeader("Expires", System.currentTimeMillis()+1000L*3600*24*30);
//这样只是读取到这样的文件但是并没有实现下载功能
InputStream in=new FileInputStream(this.getServletContext().getRealPath("1.jpg"));
OutputStream out=response.getOutputStream();
byte[]bs=new byte[1024];
int i=0;
i=in.read(bs);
while(i!=-1){
out.write(bs,0,i);
i=in.read(bs);
}
in.close();
///下载的形式应该用这个方式
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//设置响应头信息在浏览器中不进行缓存
response.setIntHeader("Expires", -1);
response.setHeader("Cache-control","no-cache");
response.setHeader("Pragma","no-cache");
//同时设置服务器和浏览器的编码方式
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("当前时间是:"+new Date().toLocaleString());
}
复制代码
设置资源下载
文件名中包含中文,则文件名要进行URL编码,URLEncoding.encode(‘啊啊.jpg’,’utf-8′);如果不进行编码则文件名显示错误并且不可下载
///下载的形式应该用这个方式 翻译:Disposition:配置
response.setHeader("Content-Disposition", "attachment;filename=1.jpg");
//这样只是读取到这样的文件但是并没有实现下载功能
InputStream in=new FileInputStream(this.getServletContext().getRealPath("1.jpg"));
OutputStream out=response.getOutputStream();
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
///下载的形式应该用这个方式(Y)
//setHeader头信息不支持中文格式所以命名不能用中文命名这样可以指定下载是所显示的名字
//response.setHeader("Content-Disposition", "attachment;filename=美女.jpg");
//方式一:狭隘
//response.setHeader("Content-Disposition", "attachment;filename=butiful.jpg");
//解决方式二:url编码可以用ascII码中的转换为url编码然后再转换为指定的编码
response.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode("美女.jpg","utf-8"));
//这样只是读取到这样的文件但是并没有实现下载功能(N)
InputStream in=new FileInputStream(this.getServletContext().getRealPath("1.jpg"));
OutputStream out=response.getOutputStream();
byte[]bs=new byte[1024];
int i=0;
i=in.read(bs);
while(i!=-1){
out.write(bs,0,i);
i=in.read(bs);
}
in.close();
}
复制代码
请求重定向
response.sendRedirect(“/Test/index.jsp”);
设置刷新跳转
response.setHeader("refresh", "3;url=/Test/index.jsp");
转发//request.getRequestDispatcher("/index.jsp").forward(request, response);
包含/request.getRequestDispatcher("/index.jsp").include(request, response);
重定向response.sendRedirect("/Test/index.jsp");
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//隔几秒刷新页面
//response.getWriter().write(new Date().toString());
//response.setHeader("Refresh", "1");
//隔几秒会到主页
//response.setCharacterEncoding("utf-8");
//response.setHeader("Content-Type", "text/html;charset=utf-8");
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("恭喜你注册成功 3秒后跳转页面....");
response.setHeader("refresh", "3;url=/Test/index.jsp");
//但是一般不会这样写会把写出的话放到html页面中
//向newFilehtml那样进行操作可以在html中用<meta http-equiv="" content="">来模拟响应头信息
}
复制代码
以上就是分享的请求和响应的技术,但是随着前后端的分离,我们现在大多数都采用response进行直接写数据到那个位置,而往往是大多数的框架帮我帮我们做了一些事情,但是我们也应该去真正的明白其中的内涵.喜欢的关注一下,同时也希望你提出宝贵的建议。