Response&Request

Response&Request

一、介绍

Web服务器每收到一次http请求,针对每一个请求,都会创建一个代表请求的request对象和
一个代表响应的response对象。Response其实就是响应客户端请求的对象。它可以用来给客户端写数据。

二、作用

1 : 写响应行

setStatus(int sc) : 设置状态码

2 : 写响应头

**sendRedirect(String location)** : 请求重定向 
setHeader(String name,String value) : 设置响应头信息

    // 告知客户端不缓存

    response.setHeader("pragma","no-cache");
    response.setHeader("cache-control","no-cache");
    response.setDateHeader("expires",0); 

    // 设置多少秒后刷新到指定路径的页面
    response.setHeader("refresh","count;url");

3 : 写响应体

**getWriter()** : 获取当前response对象的字符输出流
getOutputStream() : 字节输出流

三、解决中文乱码问题

因为服务器响应默认写出编码是 ISO-8859-1 , 与客户端解析的编码不一致 , 会导致中文乱码。

解决方案一:

//告诉服务器Tomcat以utf-8编码写出去
response.setCharacterEncoding("utf-8"); 

//告诉客户端(浏览器)以utf-8编码解析相应回去的内容
response.setHeader("Content-Type", "text/html;charset=utf-8");


解决方案二:

//这种方法封装了上面两个方法,包含了上面两个方法的意思
response.setContentType("text/html;charset=utf-8");

Request

一、介绍

Request是代表客户端请求的一个对象,用于对请求进行操作的对象。

二、作用

下面以在http://localhost:8080/WebTest/index.html的提交表单测试以下方法

1 : 存 | 取数据

request.setAttribute(name,value) 
request.getAttribute(name)

2 : 获取请求消息行信息

**request.getContextPath() : 获取当前项目的路径
request.getRequestURL() : 获取    
request.getRequestURI()

request.getMethod() : 获取请求提交的方式
request.getProtacal() : 获取请求使用的协议版本
request.getremoteHost() : 获取访问的地址   
    ......


测试:

// Request获取消息行信息的方法:
    
System.out.println(request.getContextPath());       /WebTest
System.out.println(request.getMethod());            POST
System.out.println(request.getRequestURL());        http://localhost:8080/WebTest/demo

System.out.println(request.getRequestURI());        /WebTest/demo
System.out.println("=========================");

getQueryString()只能获得拼在地址栏get方式提交的数据
System.out.println(request.getQueryString());       username=jerry&password=123&password=123

System.out.println(request.getProtocol());          HTTP/1.1
System.out.println(request.getRemoteAddr());        0:0:0:0:0:0:0:1
System.out.println(request.getRemoteHost());        0:0:0:0:0:0:0:1
System.out.println(request.getRemoteUser());        null

3 : 获取请求消息头信息

**request.getHeader(name) : 获取指定消息头的信息
request.getHeaderNames(name) : 获取指定属性名的所有消息头,返回Enumeration枚举项数组
request.getHeaders(name) : 获取消息头字段为name的所有消息头。返回Enumeration枚举项
-------------------------------------------
request.getDateHeader()
request.getIntHeader()


// Request获取消息头信息的方法:

// 获取单个信息头的值:request.getHeader(name)
System.out.println(request.getHeader("User-Agent"));
System.out.println("-----------------------------");
结果:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3013.3 Safari/537.36  


//获取消息头为指定名称的多个值
//request.getHeaders(name)

// 获取所有的信息头的名称:request.getHeaderNames()
Enumeration names = request.getHeaderNames();
while (names.hasMoreElements()) {
    // 遍历获取每一个消息头名称:
    String name = (String) names.nextElement();
    // 获取每一个信息头对应的值:
    String header = request.getHeader(name);
    System.out.println(name + " : " + header);
}   
Response&Request_第1张图片
测试结果.png

4 : 获取请求提交的参数的信息

**request.getParameter(name) : 获得参数名为name的单个参数的值
request.getParameterNames() : 获得提交数据的所有参数名,返回Enumeration对象
**request.getParameterMap : 将请求消息的所有参数的名称和值存放入一个map集合中,并返回map集合
---------------------------------------------------------
request.getParameterValues(name) : 获得参数名为name的所有参数的值,返回String数组


测试:

    // Request获取参数的方法:

    // 获取单个参数:request.getParameter(name)
    System.out.println(request.getParameter("username"));
    System.out.println("=============================");
    
    // 获取参数名相同的多个参数值:
    String[] values = request.getParameterValues("password");
    System.out.println(Arrays.toString(values));
    System.out.println("=============================");
    
    // 获取所有参数名
    Enumeration names = request.getParameterNames();
    while (names.hasMoreElements()) {
        // 获取每一个参数名
        String name = (String) names.nextElement();
        // 获取每一个参数名对应的值
        String value = request.getParameter(name);
        System.out.println(name + " : " + value);
    }
    System.out.println("=============================");

    // 获取所有的参数与参数值的map集合
    Map parameterMap = request.getParameterMap();
    // 增强for遍历map集合,输出参数名和他的值
    for (Entry set : parameterMap.entrySet()) {
        String key = set.getKey();
        String[] strings = set.getValue();

        if (strings.length == 1) {  
            System.out.println(key + "---" + strings[0]);
        } else {
            System.out.println(key + "---" + Arrays.toString(strings));
        }
    }       
Response&Request_第2张图片
测试结果.png

5 : request对象处理中文乱码问题

客户端提交数据有时候会有中文,而在客户端(如浏览器)的HTML页面默认以UTF-8的编码进行解码,将提交的数据
解析成二进制,但是当服务器(Tomcat)接收到提交的数据后,服务器会以默认的编码:ISO-8859-1编码,因此会
出现中文乱码现象。处理乱码GET请求和POST请求的处理方式如下:
  • POST请求提交中文到服务器

      请求对象中告诉服务器以UTF-8进行编码:
      request.setCharacterEncoding("UTF-8")  
    
  • GET请求

      服务器通过getParameter(name)获得的参数经过ISO-8859-1编码,将它重新变为byte字节数组,然后UTF-8的格式重新编码
    
      例如:
          filename = new String(filename.getBytes("ISO-8859-1"),"UTF-8");
    

还是以上面的页面进行测试:

Response&Request_第3张图片
Get请求.png
在姓名输入框中输入:林志玲
在没有进行中文处理之前,点击确定显示乱码
GET请求结果.png
GET方式处理乱码:
    
//获取要处理的参数username
System.out.println(request.getMethod());
String username = request.getParameter("username");
//将以ISO-8859-1编码的username参数重新以UTF-8编码
username = new String(username.getBytes("ISO-8859-1"),"UTF-8");
System.out.println(username);
System.out.println("=============================");
GET中文2乱码处理后.png
POST方式处理乱码:

//告诉服务器以指定格式的编码进行编码
request.setCharacterEncoding("UTF-8");

System.out.println(request.getMethod());
System.out.println(request.getParameter("username"));  
POST请求处理后.png

三、作用域

request对象是在服务器接收到请求时,在service()方法调用之前就创建了,在服务器对客户端做出响应之后销毁。
  • 生命周期

    • 创建:
      • 产生一个请求时创建request对象
    • 销毁
      • 服务器对客户端做出响应后

正是由于request对象生命周期,也决定了request对象的作用域只能在当次请求有效。
因此它与ServletContext不同,ServletContext的作用域在当前项目下都有效。

四、页面跳转(重定向与请求转发)

1、 重定向

由response对象处理,响应给客户端,让它跳转页面

原始版本:

    //告诉客户端要进行重定向操作
    response.setHeader(302);
    //告诉客户端要跳转的页面
    response.setHeader("Location",url);

封装后:
    response.sendRedirect(url);
Response&Request_第4张图片
重定向请求图解

2、请求转发

由request对象处理。

请求转发:
request.getRequestDispatcher(url).forward(ServletRequest req,ServletResponse resp);

请求包含:(相当于把后面那个页面的代码追加到前面这个页面)
request.getRequestDispatcher(url).include(ServletRequest req,ServletResponse resp);
Response&Request_第5张图片
请求转发的请求图解

五、案例

1:下载服务器文件位置在Resource中的资源

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

    // System.out.println(this.getServletContext().getRealPath(""));
    // D:\Develop\apache-tomcat-7.0.52\wtpwebapps\day16_DownLoadDemo
    // 默认访问的是服务器当前项目的根目录
    // 1.点击下载发送请求,就会将其要下载的文件路径发送过来,使用request获取要下载资源的文件名
    String filename = request.getParameter("filename");
    System.out.println("文件名处理前:"+filename);
    // 1.1 获取要下载文件的类型,现在浏览器会帮忙处理 
    String mimeType = this.getServletContext().getMimeType(filename);
    response.setHeader("Content-Type", mimeType);
    System.out.println(mimeType);
    request.setCharacterEncoding("UTF-8");
    //让服务器与客户端使用的编码一致
    response.setContentType("UTF-8");
    
    // 2.下载文件
    // 获取到的filename参数是通过GET方式发送的,为了防止中文乱码
    filename = new String(filename.getBytes("ISO-8859-1"), "utf-8");
    System.out.println("文件名处理后:"+filename);

    // 通过资源的相对路径获得该资源的全路径
    String realPath = this.getServletContext().getRealPath("Resource/" + filename);

    // 为了在下载时能够使中文能正确在浏览器的URL栏正确显示,需要对filename再做一次URL编码处理
    // 获取浏览器的信息
    String agent = request.getHeader("User-Agent");
    System.out.println(agent);
    // Firefox使用的是Base64的编码,而IE和谷歌等下载中文文件时使用的是URL编码
    if (agent.toLowerCase().contains("firefox")) {
        filename = base64EncodeFileName(filename);
    } else {
        filename = URLEncoder.encode(filename,"UTF-8");
    }
    
    //设置下载时的确认框Content-Dispositon
    response.setHeader("Content-Dispositon", "attachment;filename="+filename);
    //获取输入流
    InputStream is = new FileInputStream(realPath);
    //获取输出流
    ServletOutputStream os = response.getOutputStream();
    
    int len = 0;
    byte[] bys = new byte[1024];
    
    while ((len = is.read(bys)) != -1) {
        os.write(bys, 0, len);
    }
    
    os.close();
    is.close();
}

public static String base64EncodeFileName(String fileName) {
    BASE64Encoder base64Encoder = new BASE64Encoder();
    try {
        return "=?UTF-8?B?" + new String(base64Encoder.encode(fileName.getBytes("UTF-8"))) + "?=";
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }
}
Response&Request_第6张图片
文件下载案例.png

2:使用验证码工具包完成验证码更换功能

Servlet响应类:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //导入验证码工具jar包,ValidateCode.jar
    
    //创建获取验证码对象
    ValidateCode validateCode = new ValidateCode(120, 40, 4, 12);
    
    //获取验证码,可以用于与用户校对    
    //String code = validateCode.getCode();
    
    //谁发送请求过来,就将验证码写给谁
    validateCode.write(response.getOutputStream());
}
Html页面:

难点:

  • 除了每次访问页面会发送一次请求,src和href也会发送一次请求,他们发送请求到Servlet,服务器对其做出响应。

  • 为了实现点击验证码图片能够完成更换验证码功能,为其添加了onclick点击事件,但会发现点击一次之后就不再变化了,这是因为浏览器缓存了验证码图片。在请求的地址后面添加参数,让其每次的请求地址都不同,这样就可以避免这个问题。

  • 在后面添加a标签:看不清换一张。如果直接在a标签中绑定点击事件href即使不填,也会跳到一个新的空白页面。为了让其不跳转页面,href="javascirpt:changeCode()"。javascript的意思是告诉html页面href后面跟的不是url地址,让其直接调用changeCode()方法

      
Response&Request_第7张图片
验证码案例.png

你可能感兴趣的:(Response&Request)