tomcat
tomcat基础
http工作原理
http协议是浏览器与服务器之间的数据传送协议.作为应用层协议,http是基于tcp/ip协议来传递数据的(html文件,图片,查询结果等),http协议不涉及数据包传输,主要规定了客户端和服务器之间的通信格式.
流程
1.用户通过浏览器执行了一个操作,比如访问网址,或者点击链接,浏览器获取了这个事件
2.浏览器向服务器发出了tcp链接的请求
3.服务器接收浏览器的连接请求,并经过tcp三次握手建立连接
4.浏览器将请求数据打包成一个http协议格式的数据包
5浏览器将该数据包推入网络,数据包经过网络传输,最终更达到端服务程序.
6浏览器程序拿到这个数据包后,同样以http协议格式解包,获取到客户端的示意图.
7得知客户端意图后进行处理,比如提供静态文件或者调用服务端程序获得动态效果.
8.服务器响应结果按照http协议格式打包
9.服务器将响应数据包推入网络,数据包经过网络传输最终到达浏览器
10浏览器拿到数据后,以http协议解包,如何解析数据,假设数据是html
11 浏览器将html文件展示在页面上
http
http服务器不直接调用业务类,而是把请求交给容器来处理,容器通过servlet调用业务类接口和Servlet容器的出现,达到了http服务器与业务类解耦的目的,而Servlet接口和Servlet容器这一整套规范叫做Servlet规范.tomcat按照Servlet规范要求实现了Servlet容器,同时他们也具有http服务器的功能.
servlet容器工作流程
为了解耦,服务器不会直接调用servlet,而是把请求交给servlet来处理
当客户端有摸个请求时http服务器会用一个ServletRequest对象吧客户的请求信息封装起来,如何调用Servlet容器的Service方法,servlet容器拿到请求后,根据请求的url和servlet的映射关系,找到相应的servlet,如果servlet还没有被加载,就用反射机制创建这个servlet,并调用servlet的init方法来完成初始化,借着调用servlet的service方法来处理请求,吧servletResponse对象返回给http服务器
tomcat整体架构
tomcat实现了俩个核心功能:
处理socket连接,负责网络字节流与request和response对象的转化
加载和管理Servlet,以及处理request请求
因此tomcat设计了俩个核心组件连机器(Connector)和容器(Container)来分别做这俩件事情.连接服务器负责对外交流,容器负责内部处理
连接器
coyote是tomcat的连接器框架名称,是tomcat服务器提供的客户端访问的外部接口.客户端通过coyote与服务器建立连接,发送请求并接受响应.
coyote封装了底层的网络通信(Socket请求及响应处理),为catalina容器提供了统一的接口,使Catalina容器与具体的请求协议及IO操作方式完全解耦.coyote将socket输入转换为Request对象,交由Catalina容器处理,处理完成之后,catalina通过coyote提供的Response将对象结果写入输出流
coyote作为独立模块,只负具体协议和io相关的操作,与Servlet规范实现没有直接关系,因此即便是Request和Response对象也并未实现Servlet规范对应的接口,而是在catalina中将他们进一步封装为ServletRequest和servletresponse.
IO模型与协议
在coyote中,tomcat支持多种I/O模型和协议,具体包含哪些IO模型和应用层协议,请看下表
tomcat支持的
tomcat支持的IO模型
IO模型 | 描述 |
---|---|
NIO | 非阻塞I/O,采用java NIO类库实现 |
NIO2 | 异步I/O,采用JDK7最新的NIO2类库实现 |
ARP | 采用Apache,是c/c++编写的本地库.如果选择该方案需要单独安装APR库 |
tomcat支持的应用层协议 |
应用层协议 | 描述 |
---|---|
Http/1.1 | 这是大部分Web应用采用的访问协议 |
AJP | 用于和Web服务器继承(入apache),实现静态资源的优化以及集群部署,当前指出AJP/1.3 |
HTTP/2 | HTTP2.0大幅度提升了Web性能,下一代HTTP协议,自8.5以及9.0版本之后支持 |
response
response响应过程
在发送一个请求时,会找到服务器引擎(tomcat),引擎会找到对应的web应用并创建request对象和reponse对象,并且创建request对象和response对象,找到应用后会执行应用web.xml在根据url-patten的内容创建servlet对象.吧request和response对象传入到方法中,拿到response对象后自己可以往响应中写入一些自己给客户端的内容,写的内容是存到一个response缓冲区中,当方法执行结束之后,tomcat就会从response缓冲区当中读取数据
设置响应行reponse.setState(int code)
默认是200
添加响应头response.addHeader("name","123123")
设置date类型response.addDateHeader("my-Date",new Date().getTime());
设置int类型的值为int类型的头信息response.addIntHeader("qqq",1);
- setHeader(name, value):如果Header中没有定义则添加,如果已定义则用新的value覆盖原用value值。
- addHeader(name, value):如果Header中没有定义则添加,如果已定义则保持原有value不改变。
重定向
response.setStatus(302);//设置状态码
response.setHeader("location","/qqq");//设置重定向地址
也可以只写一行
response.setHeader("refresh","10;url=/admin/index");//过10秒之后去转发
响应体
设置响应体
response.getWriter().write("!@3");
//写文件
File file = new File(url);
HttpHeaders headers=new HttpHeaders();
//告诉浏览器以附件的形式打开,并且设置文件名的编码,防止乱码
//通过ServletContext获取文件名对应的mime类型
String mimeType = request.getSession().getServletContext().getMimeType(filename);
response.setContentType(mimeType);//这么写的话可以直接解析图片或者mp4之类的文件
response.setHeader("Content-Disposition","attachment;filename="+URLEncoder.encode(filename,"UTF-8"));//加上这行就能实现下载
try(
InputStream is = new FileInputStream(file);
ServletOutputStream os = response.getOutputStream();//写在这里,执行结束会自动关闭输入输出流
){
int read = 0;
byte[] bytes = new byte[2048];
while ((read = is.read(bytes)) != -1)
os.write(bytes, 0, read);
}
以上俩个只能选一种
设置编码
浏览器默认使用的是iso8859编码,不支持中文,可以设置
response.setCharacterEncoding("UTF-8");//设置缓冲区当中的编码
response.setHeader("Content-Type","text/html;charset=UTF-8");//设置编码,
Request
Request 和 Response 对象起到了服务器与客户机之间的信息传递作用。Request 对象用于接收客户端浏览器提交的数据,而 Response 对象的功能则是将服务器端的数据发送到客户端浏览器。
请求行
获取
request.getMethod();//获取请求方式
request.getRequestURI();//获取从更目录之后的请求路径
request.getRequestURL();//获取带上域名的请求完整路径
request.getQueryString();//获取字符串格式的请求参数
请求头
获取
//枚举集合
Enumeration<String> headerNames = request.getHeaderNames();//获取全部请求头的名称
while (headerNames.hasMoreElements()){
System.out.println(headerNames.nextElement());
}
request.getHeader("cookie")//获取指定请求头的指定内容
request.getHeader("referer")//获取浏览器的上一个界面
referer
用a标签,或者表单提交js跳转等,是有referer的
但是如果是直接访问的,收藏夹,或者在浏览器当中直接输地址是没有referer的
获取请求参数
System.out.println(request.getParameter("name"));//获取一个name值
String[] names = request.getParameterValues("name");//获取多个值的name,比如复选框
Enumeration<String> parameterNames = request.getParameterNames();
//遍历获取所有的参数名称
Enumeration<String> parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()){
System.out.println(parameterNames.nextElement());
}
//获取全部的请求参数
Map<String,String[]> parameterMap = request.getParameterMap();
请求转发
RequestDispatcher disp = request.getRequestDispatcher("/admin/user/userlist");
disp.forward(request,response);//springmvc中不能这样处理用:return "forward:/hello";