JavaSE02_Day04(上) -WebServer项目(四):响应客户端资源

版本四

(1)在WebServer主类中的strat方法中添加while循环,这样可以让服务端一直可以接收新的客户端连接;

(2)根据请求将客户端需要的资源响应回去

  1. 在项目中新建一个可以存放"网站资源"的总目录webapps ,Tomcat中也是这么做的,每一个网站都可以称之为webapps,包含该网站的资源(网页,图片等等);

  1. 在webapps下建立一个子目录:myweb,作为我们测试使用的web应用 ;

  1. 在myweb目录下新建第一个页面:index.html ;

  1. 在ClientHandler类中根据request获取客户端请求的资源路径,然后去对应的webapps 下找到该资源并进行判断处理 ;

  1. 添加响应404页面的操作,当客户端请求的资源不存在时,应当响应给客户端404页面,并且状态码和描述也要与之对应 ;

  1. 在webapps目录下创建root目录,在这里创建404.html网页,这是一个公共页面,无论请求应用中的哪一个资源,只要不存在就会响应这个页面 ;

  1. 在ClientHandler类中处理请求的分支中,如果资源没有找到,将webapps/root/404.html设置好,将页面响应给客户端。

 

新建首页index.html页面

  在项目下新建webapps,在该目录下进行新建myweb目录,然后在myweb目录下进行新建index.html首页

 <!DOCTYPE html>
 <html>
     <head>
         <meta charset="UTF-8">
         <title>我的首页</title>
     </head>
     <body>
         <center>
             <h1>谷歌</h1>
             <input type="text" size="40">
             <input type="button" value="谷歌查询" onclick="alert('查询无效!!!')">
         </center>
     </body>
 </html>

 

新建404.html页面

  在项目的webapps目录下,新建root目录,在root目录下新建404.html页面

 <!DOCTYPE html>
 <html>
     <head>
         <meta charset="UTF-8">
         <title>404页面</title>
     </head>
     <body>
         <center>
             <h1>404资源未找到!!!</h1>
         </center>
     </body>
 </html>

设置不同的客户端均可被服务器接收

测试:在浏览器输入http://localhost:8888/myweb/index.html

测试输出结果:

 正在启动服务器端......
 服务器端已经启动成功!
 正在等待客户端连接......
 一个客户端已经连接完毕!
 HttpRequest开始解析请求......
 开始解析请求行......
 请求行:GET /myweb/index.html HTTP/1.1
 method:GET
 url:/webapps/myweb/index.html
 protocal:HTTP/1.1
 解析请求行完毕!
 开始解析消息头......
 Host: localhost:8088
 Connection: keep-alive
 Cache-Control: max-age=0
 sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"
 sec-ch-ua-mobile: ?0
 Upgrade-Insecure-Requests: 1
 User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36
 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
 Sec-Fetch-Site: none
 Sec-Fetch-Mode: navigate
 Sec-Fetch-User: ?1
 Sec-Fetch-Dest: document
 Accept-Encoding: gzip, deflate, br
 Accept-Language: zh-CN,zh;q=0.9
 解析消息头完毕!
 开始解析消息正文......
 解析消息正文完毕!
 HttpRequest解析请求完毕!
 /myweb/index.html
 keep-alive

ClientHandler类响应客户端请求的数据

 package cn.tedu.core;
 
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.Socket;
 
 import cn.tedu.http.HttpRequest;
 
 /**
  * 处理客户端请求的任务序列类
  * @author cjn
  *
  */
 public class ClientHandler implements Runnable{
  //声明连接客户端后获取的socket对象
  private Socket socket;
 
  /**
  * 构造器
  * @param socket 连接客户端后获取的socket对象
  */
  public ClientHandler(Socket socket){
  this.socket = socket;
  }
 
  /**
  * 线程所执行的任务序列逻辑
  */
  public void run() {
  try {
  //创建HttpRequest对象
  HttpRequest request = new HttpRequest(socket);
  //测试解析请求的相关内容
  System.out.println(request.getUrl());
  System.out.println(request.getHeaders("Connection"));
 
  /**
  * 对用户的请求进行响应:
  * 1.需要获取用户请求的资源路径
  * 2.根据用户请求的资源,在当前项目中进行查找并响应资源
  */
  //获取Url
  String requestUrl = request.getUrl();
  //获取资源路径
  File file = new File("webapps" + requestUrl);
  //判断是否可以找到index.html首页资源
  if(file.exists()){
  System.out.println("找到资源页面");
  //获取输出流对象,向客户端写出相关数据内容
  OutputStream out = socket.getOutputStream();
  //发送状态行
  String line = "HTTP/1.1 200 OK";
  //指定字符集IISO8859-1
  out.write(line.getBytes("ISO8859-1"));
  //发送CRLF作为结束标志
  out.write(13);
  out.write(10);
    
  //通过输出流对象发送响应头,响应对应页面资源
  line = "Content-Type: text/html";//媒介类型
  out.write(line.getBytes("ISO8859-1"));
  out.write(13);//发送CRLF
  out.write(10);
 
  line = "Content-Length: " + file.length();
  out.write(line.getBytes("ISO8859-1"));
  out.write(13);//发送CRLF
  out.write(10);
  //当响应头写出完毕后末尾还需要写出一个CRLF
  out.write(13);//发送CRLF
  out.write(10);
 
  /*
                  * 通过输出流对象发送响应正文
                  * 注意:不能使用上面的out对象进行发送响应正文(index.html),
                  * 因为这个输出流对象是通过连接客户端获取的socket对象得到的输出流对象,
                  * 当前发送响应正文,实际是需要将服务端中的index.html页面资源发送给客户端,
                  * 需要使用到服务端自己的输出流对象进行写出数据,也就是Java内部获取输出流对象,
                  * 将服务器内部的资源进行写出。
                  * 1.先将服务器端的文件资源读取到内存中
                  * 2.然后再使用输出流对象进行写出操作
                 */
  FileInputStream fis = new FileInputStream(file);
  byte[] data = new byte[1024*10];
  int len = -1;
  while((len=fis.read(data))!=-1){
  out.write(data,0,len);
          }  
    }else{ 
          System.out.println("未找到资源页面"); 
          //未找到资源响应404页面 
          File notFoundFile = new File("webapps/root/404.html"); 
          //获取输出流对象 
          OutputStream out = socket.getOutputStream(); 
 
          //发送状态行 
          String line = "HTTP/1.1 400 Not Found"; 
          out.write(line.getBytes("ISO8859-1")); 
          out.write(13);//发送CRLF 
          out.write(10); 
 
          //通过输出流对象发送响应头,响应对应页面资源 
          line = "Content-Type: text/html";//媒介类型 
          out.write(line.getBytes("ISO8859-1")); 
          out.write(13);//发送CRLF 
          out.write(10); 
 
          line = "Content-Length: " + notFoundFile.length(); 
          out.write(line.getBytes("ISO8859-1")); 
          out.write(13);//发送CRLF 
          out.write(10); 
          //当响应头写出完毕后末尾还需要写出一个CRLF 
          out.write(13);//发送CRLF 
          out.write(10); 
 
          //发送响应正文 
          FileInputStream fis = new FileInputStream(notFoundFile); 
          byte[] data = new byte[1024*10]; 
          int len = -1; 
          while((len=fis.read(data))!=-1){ 
            out.write(data,0,len); 
          }  
      } 
 
  } catch (Exception e) { 
      e.printStackTrace(); 
  }  

 

测试:

  (1)启动WebServer主类,然后打开浏览器,在浏览器的地址栏中输入http://localhost:8888/myweb/index.html访问首页资源的路径,查看浏览器页面上是否显示自定义首页。

输出结果

 正在启动服务器端......
 服务器端已经启动成功!
 正在等待客户端连接......
 一个客户端已经连接完毕!
 正在等待客户端连接......
 一个客户端已经连接完毕!
 正在等待客户端连接......
 HttpRequest开始解析请求......
 HttpRequest开始解析请求......
 开始解析请求行......
 开始解析请求行......
 请求行:GET /myweb/index.html HTTP/1.1
 method:GET
 url:/myweb/index.html
 protocal:HTTP/1.1
 解析请求行完毕!
 开始解析消息头......
 Host: localhost:8888
 Connection: keep-alive
 Cache-Control: max-age=0
 sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"
 sec-ch-ua-mobile: ?0
 Upgrade-Insecure-Requests: 1
 User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36
 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
 Sec-Fetch-Site: none
 Sec-Fetch-Mode: navigate
 Sec-Fetch-User: ?1
 Sec-Fetch-Dest: document
 Accept-Encoding: gzip, deflate, br
 Accept-Language: zh-CN,zh;q=0.9
 解析消息头完毕!
 开始解析消息正文......
 解析消息正文完毕!
 HttpRequest解析请求完毕!
 /myweb/index.html
 keep-alive
 找到资源页面

  (2)在浏览器的地址栏中输入http://localhost:8888/myweb/index111.html访问不存在的资源,查看当前在浏览器页面上是否显示404自定找不到资源页面。

输出结果

 正在启动服务器端......
 服务器端已经启动成功!
 正在等待客户端连接......
 一个客户端已经连接完毕!
 正在等待客户端连接......
 一个客户端已经连接完毕!
 正在等待客户端连接......
 HttpRequest开始解析请求......
 开始解析请求行......
 HttpRequest开始解析请求......
 开始解析请求行......
 请求行:GET /myweb/index111.html HTTP/1.1
 method:GET
 url:/myweb/index111.html
 protocal:HTTP/1.1
 解析请求行完毕!
 开始解析消息头......
 Host: localhost:8888
 Connection: keep-alive
 sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"
 sec-ch-ua-mobile: ?0
 Upgrade-Insecure-Requests: 1
 User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36
 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
 Sec-Fetch-Site: none
 Sec-Fetch-Mode: navigate
 Sec-Fetch-User: ?1
 Sec-Fetch-Dest: document
 Accept-Encoding: gzip, deflate, br
 Accept-Language: zh-CN,zh;q=0.9
 解析消息头完毕!
 开始解析消息正文......
 解析消息正文完毕!
 HttpRequest解析请求完毕!
 /myweb/index111.html
 keep-alive
 未找到资源页面

  注意:如果在测试的过程中,整个浏览器页面显示的资源都正确,但是服务器端控制台中有空指针异常的报错时,这个问题后面会解决,因为浏览器有时会发送空请求,当发送空请求以后,对请求进行解析拆分时,当前就不能够拆分出三项,后面会对这块单独进行处理。

posted @ 2021-07-14 10:35  Coder_Cui  阅读(121)  评论(0编辑  收藏  举报