# webserver **Repository Path**: qiaobilong/webserver ## Basic Information - **Project Name**: webserver - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-08-20 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 【WebServer_v20】 现在,每当我们添加一个新的业务时,我们除了准备该业务需要的页面和处理该业务的Servlet之外,还要在ClientHandler添加一个分支判断。 我们需要通过配置文件来告诉ClientHandller多一个一个新的请求并对应哪个业务类处理,使其调用service方法 1. 首先,我们需要定义一个超类,HttpServlet,并定义抽象方法service,并让所有Servlet都集成它 2. 通过获取xml中请求和Servlet的对应关系实现动态实例化 添加日志功能 # 【WebServer_v19】 使用线程池维护处理客户端交互的线程。 # 【WebServer_v18】 支持post请求提交form表单 想获取post形式提交的数据,就需要HttpRequest中实现解析消息正文的工作 # 【WebServer_v17】 完成二维码生成功能 过程: 用户访问生成二维码的页面,并输入要在二维码上显示的内容,并点击生成按钮提交数据。 请求line→Servlet→响应图片 实现: 1. 在webapps/myweb目录下新建一个页面:createQR.html,并在index.html加上超链接 2. createQR.html上定义一个表单,一个输入框,提交路径createQR 3. 新建一个CreateQRServlet,并定义service方法 4. ClientHandler中加分支,请求生成二维码就实现Servlet并调用service # 【WebServer_v16】 使用Thymeleaf,生成动态页面 动态页面:还有动态资源(数据)的页面 - 动态资源(数据):通过程序生成的数据,比如验证码 - 静态资源(数据):事先准备好的,不会变的,比如图片,HTML页面等 本版本需求:在一个页面上显示所有注册用户的信息。 该页面上展示的用户数据来源于user.dat。该文件随着用户做注册修改等操作随时变化,因此展示注册用户的页面不可能是事先准备好的不变的内容,因此该页面上的用户数据是程序每次根据请求该页面时生成并体现到页面上的。 thymeleaf是一个用于生成动态页面的框架,可以在html代码中添加少量的标签即可和程序生成的数据进行结合,生成一个含有这些数据并且样子还是HTML代码样子的页面。 实现: 1. 组建页面上要使用的数据 2. 创建显示数据的静态页面 3. 用thymeleaf将数据绑定到页面上生成一个含有动态数据的页面,并最终响应给客户端展示。 步骤: 1. 定义一个业务处理类:UserListServlet,并实现service方法 2. 定义一个表示用户信息的类:User,该类每一个实例用于表示一个用户 3. 在webapps/myweb目录下新建一个静态页面:userList.html 4. service方法中读取user.dat文件中的所有数据,并利用thymeleaf将数据绑定到userList.html中生成含有所有用户信息的页面并响应 # 【WebServer_v15】 完成用户登录操作 登录的流程: 1. 用户访问登录页面(可在首页上点击超链接进入登录) 2. 在登录页面输入用户名和密码并点击登录按钮提交表单 3. 表单提交路径action=“loginUser” 4. ClientHandler处理请求环节发现是这个请求时,就实例化一个处理登录的业务类LoginServlet,并调用它的service方法处理 5. LoginServlet处理中如果用户输入的用户名密码都对,则设置响应登录成功页面:login_success.html,否则设置响应登录失败:login_fail.html,登录失败有两种情况:用户名不对,或者用户名对,但密码不对。 # 【WebServer_v14】 解决传递中文问题 问题: 当我们注册页面上输入中文,那么提交这个表单如果使用GET形式的话,输入框的内容都会包含在地址栏的“?”右侧。而这部分信息最终会体现在请求的请求行中的抽象路径部分里HTTP协议要求请求的请求行和消息头出现的字符只能符合ISO8859,这个字符集中不支持中文,因此我我们不能直接传递中文给服务端。 解决办法: 浏览器会将中文先按照指定的字符集转换为一组字节,然后每个字节用两位16进制形式表示,并在前面用一个%标注,形成%xx这样的内容以此表示一字节信息,这个是URL地址格式规定的。因此,服务端在接收到这些%xx的内容后可以再将xx部分的16进制还原为2进制,在按照浏览器使用的字符集还原对应的文字即可。 注:16进制出现的字符只有:0123456789ABCDEF,这些字符iso8859-1都支持,所以我们用这样的形式传递即可,HTTP协议要求,又可以做到传递非ISO8859-1的字符内容了。 # 【WebServer_v13】 完成用户注册的业务处理 上一个版本中我们在注册页面上的表单中action=“./regUser”,解析请求后获得一个请求:/myweb/regUser,所以我们需要用requestURI替换原有的uri。 因此ClientHandler处理请求的环节,首先获取requestURI的值作为请求,然后加一个分支判断,看看他的值是不是注册页面,表单提交上来的“/myweb/regUser”,如果是则处理用户注册,否则再执行原来的分支,看看是不是webapps的一个文件。 这样一来,在用户注册页面提交表单时,则会走到处理用户注册的分支,我们来完成这个工作: 1. 新建一个包:com.webserver.servlet,在这个包中保存所有用于处理某个特定业务的类 2. 在servlet包中新建类:RegServlet用于处理用户注册业务 3. 在ClientHandler的处理请求环节添加新分支判断,如果请求路径是“/myweb/regUser”则实例化RegServlet实例去完成注册。 在RegServlet中增加对输入内容的验证,要求数据正确输入,否则返回login_info_err.html # 【WebServer_v12】 上一个版本已经完成了对静态资源的完整响应工作。 本版本开始,完成业务的处理,这里先以实现注册用户为例开始实现 需要了解的知识点: 1. 浏览器如何将用户在页面上输入的信息提交给服务端,了解页面中的"表单"元素。 2. 服务端如何通过浏览器发送过来的请求解析到用户提交的数据 本版本先将上述两个工作完成,因为他是通用的,无论用户将来完成什么业务,只要提交数据,解析工作是一样的。 这一步完成后,在下一个版本中实现具体的处理注册用户的业务步骤。 实现: 1. 在webapps/myweb/下新建一个页面:reg.html,注册页面,在这里学习表单的使用。 2. 重构HttpRequest类,完成解析用户提交表单数据的操作。 # 【WebServer_v11】 tomcat中有个一个conf目录,里面有个web.xml文件,这个文件中记录了所有的资源类型,我们直接将这个文件的内容解析出来初始化mimeMapping。 实现: 1. 在项目目录下新建一个config目录 2. 将web.xml文件拷贝到目录下 3. 在HttpContext初始化mimeMapping方法中通过解析xml,将1000多种对应关系存入到Map中 # 【WebServer_v10】 将存放Content-Type数据的Map定义为静态的,全局一份即可。 实现: 1. 在com.webserver.http包中新建一个类:HttpContext,使用这个类保存所有和HTTP协议相关固定不变的内容 2. 新建一个静态属性,是一个Map,保存所有Content-Type的值和资源后缀名的对应关系 3. 提供初始化操作和一个公开的静态方法getMimeType,可以根据资源后缀名获取到对应的Content-Type的值 4. 将ClientHandler中原有的操作改为通过此方法获取对应数据 实现: 1. 将ClientHandler中根据正文文件设置的两个响应头移动到到HttpResponse中 # 【WebServer_v9】 本版本要对响应中发送响应头的工作做2个重构 1. HttpResponse发送响应头,应该是可以扩展的 2. 发送响应头Content-Type时的值应当随着客户端请求的资源类型不同,而产生变化,让浏览器理解其请求的资源。 用Map存响应头的相关信息 # 【WebServer_v8】 封装HttpResponse中的响应的三个操作 在页面上显示一张图片,从中了解页面中含有其他资源时,浏览器与服务端的交互过程。 实现: 1. 在webapps/myweb目录下保存一张图片,名字任意。 2. 在webapps/myweb目录下的index.html页面上图片的展示 3. 通过浏览器访问服务端该页面查看图片的显示 当一个页面上含有其他资源,浏览器要通过多次请求将这些资源下载后,才能完整展示页面。 解决由于空请求导致的服务端请求解析过程中产生的数组越界异常(解决思路:parseRequestLine方法中,如果读取的字符串为空,则向上抛出EmptyRequestException异常,直到ClientHandler中,并进行相应处理。注:如果catch中为Exception会导致EmptyRequestException被拦截 ) # 【WebServer_v7】 将ClientHadnler中发送响应的实际工作拆分出去。 与请求一样,根据响应格式,设计一个类HttpResponse,用这个类的每一个实例表示给客户端发送的内容。 实现: 1.在com.webserver.http包中的新建类HttpResponse 2.定义HttpResponse的结构,以及方法flush,flush方法用于将当前响应对象的各部分信息最终以标准的HTTP响应格式发送给客户端 3.将ClientHandler处理请求的分支根据处理结果设置HttpResponse对象内容并通过调用flush方法发送响应。 # 【WebServer_v6】 此版本完成响应404页面的工作 当用户输入的路径,在服务端找不到对应文件的时候,我们就应该给用户响应一个404页面,状态码404,状态描述NotFound 实现: 1.在webapps目录下新建一个子目录root,并在这个目录下新建404页面,起名为404.html。(注:root为共用内容的存放位置) 2.在ClientHandler中处理请求的环节,创建File对象,应该进行判断,看路径是否存在,不存在则返回404页面。 # 【WebServer_v5】 此版本完成根据客户端请求的页面进行响应 首先做一个练习的操作: 在webapps目录下再新建一个字目录:myBlog 然后在这个目录下新建一个页面,内容随意发挥 完成后,在ClientHandler第二步处理请求中,完成用户通过浏览器输入地址可以请求到新页面的功能 # 【WebServer_v4】 此版本测试给客户端响应一个页面回去 在这个版本中我们要了解两个知识点: 1.HTML页面的基本语法 2.HTTP响应的格式定义,因为只有基于该格式要求才能给客户端发送响应 实现: 1.创建一个页面 1.1:在项目目录下新建一个目录webapps 这个目录用于保存服务端所有的网络应用(webapp),每个网络应用在webapps下单独以一个目录形式保存。目录命名 就作为网络应用的名字。 注:每个网络应用相当于一个“网站”,会包含如:页面,素材,以及用于处理业务的逻辑代码。 1.2:在webapps下新建第一个子目录作为我们的第一个网络应用,取名为myweb。 1.3:在myweb目录下新建第一个页面:index.html,通过该页面我们了解HTML页面的基本语法和结构。 2.测试页面将通过响应回复给客户端 在ClientHandler中的第三步响应客户端中,将刚刚定义好的页面通过发送一个标准的HTTP响应回复给客户端。并测试浏览器在 请求服务端后是否可以正确接收到响应并展示到浏览器上。响应的格式参照:http_utf-8.txt # 【WebServer_v3】 此版本要解析请求并以HttpRequest对象形式保存 上一个版本中已经测试完成了读取客户端发送过来一行字符串的操作,因此,本版本开始完成解析请求。 由于一个请求包含信息过多,因此我们设计一个类:HttpRequest,并用该类的每一个实例表示客户端发来的一个Http请求内容。 实现: 1.新建一个包com.webserver.http,将来有关http协议的类都放在这个包里。 2.在http包中新建一个类:HttpRequest,即:请求对象,这个类的实例用于表示一个具体的http请求。 3.在HttpRequest中定义构造方法,用来在实例化请求对象的同时完成请求的解析工作。 4.在ClientHandler第一步解析请求的环节中通过实例化请求对象完成解析工作。 # 【WebServer_v2】 此版本开始完成解析请求的工作 上一个版本中我们在WebServer里测试与浏览器的连接,并且读取了浏览器发送过来的请求内容 一个请求由三部分构成: 请求头、消息头都是由一行字符串构成的,特定都是以回车换行符结尾。因此正式开始解析前,先测试读取一行字符串的操作。 实现: 1.在com.webserver.core包下新建ClientHandler类,这个是线程任务,用于处理一个客户端的交互。 2.在ClientHandler中完成通过socket获取输入流并读取一行客户端发来的消息的逻辑。