Servlet 4.0新特性
适当的抽象
Servlet API已经很好地支持HTTP / 2优化,并允许框架利用服务器推送。
Servlet如何展示HTTP / 2特点?
Servlet是RFC的正确抽象。您不希望编程帧和流,因此隐藏网络层的高级API会很好。在Servlets层,你可以做服务器推出没有做低层次的东西。
一个请求和多个响应
Servlet API中的一个变化是在HTTP 1中我们有一个请求和一个响应。在HTTP/2中,这不再是唯一。可以有一个请求,服务器可能决定推送多个资源,然后最终以最初请求的页面进行响应。您同时有一个请求和多个响应,这对Servlet API来说是一个挑战。
服务器推送
服务器推送是HTTP/2中出现在servlet API中的许多改进中最明显的部分。HTTP/2中的所有新功能(包括服务器推送)都旨在提高Web浏览体验的感知性能。
改进了浏览器感知的性能
启用服务器推送可提高浏览器的性能,因为服务器比客户更能了解请求可能要求的附加资产(如图像,样式表和JavaScript)。
例如,服务器可以知道,无论何时浏览器请求index.html页面,它都会请求标识图像,样式表和菜单JavaScript等。由于服务器知道这一点,他们可以先发制人地开始发送这些资产处理index.html。
不是Web Sockets的替代品
它只是允许你填充浏览器缓存。预计构建在像JSF这样的Servlet上的框架将使用这个框架,并且我们使用push builder API来解决这个问题。
典型的流程
浏览器请求索引页面。服务器会注意到它需要style_1.css和javaScript_1.js 文件,所以我们从HTTP请求中获取PushBuilder,并将路径设置为style_1.css文件并调用push,然后将路径设置为javaScript_1。 js文件并再次调用推送。
注意在这种情况下,CSS和JavaScript将首先返回到客户端,然后index页面返回。
从HTTP请求推送生成器
只需从HTTP Request对象中获取推式生成器,并将路径设置为资源并推送即可。
在这个序列图中有两件事要注意,
- 推构建器可以重用。在示例中,我使用推式构建器将两个资源推送到CSS文件和JavaScript文件。
- 第二件事是index.html在推送资源后返回浏览器。
原因是,如果索引在推送资源之前返回,浏览器将分析它并看到它需要这两个资源。它会查看缓存并查看它没有这些资源,它会请求它们。此时,浏览器缓存将不会预填充。所以推送的资源必须在索引发送之前先返回。
推送答应
前面提到的其中一种框架类型是 RST_STREAM, 这就是客户如何拒绝推送承诺。因此,如果服务器推送一个资源,并且浏览器已经将其存储在缓存中,那么不是让服务器发送文件,而是发送一个RST_STREAM 帧,表明它已经有文件文件,因此不发送它。
PushBuilder
要使用服务器推送,从HttpServletRequest获取对PushBuilder 的引用,根据需要改变生成器,然后调用 push() 方法。
PubshBuilder pubshBuilder= request.getPubshBuilder();
这会根据从中获取此构建器的HttpServletRequest构建推送请求
这会根据从中获取此构建器的HttpServletRequest生成推送请求。
javax.servlet.http.PushBuilder类
推送请求由请求方法设置为GET 构建。有条件, 范围, 期望, 授权和请求标题被删除。只有在maxAge未过期的情况下才会添加Cookie 。请求标头将被设置为请求URL和存在的任何查询字符串。如果 If-Modified-Since 或 If-None-Match 中的任何一个出现,则 isConditional() 将被设置为true。
只有URI路径必需
唯一需要的设置是要用于推送请求的URI路径。这必须在每次调用push()之前调用 。如果路径包含查询字符串,则查询字符串将附加到现有查询字符串(如果有),并且不会发生重复数据删除。
以\’/\’开头的路径被视为绝对路径。所有其他路径都视为相对于用于创建此构建器实例的请求的上下文路径。该路径可能包含查询字符串。
通过 在pushBuilder实例上调用push()方法来推送资源 。
@WebServlet("/WelcomeServlet") public class WelcomeServlet extends HttpServlet{ @Override protected void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{ if(request.getRequestURI.equals("/index.html")&&reqeust.isPubshSupported()){ request.getPushBuilder().path("/images/logo.jpg").push(); } } }
过滤器和服务器推送
解决这个问题的另一种方法是在过滤器中实现服务器推送。Jetty 在 org.eclipse.jetty.servlets 包中有一个 PushCacheFilter。
import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import org.apache.catalina.servlet4preview.http.PushBuilder; @WebFilter(urlPatterns="/*") public class PushFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpServletRequest=(HttpServletRequest)request; String uri=httpServletRequest.getRequestURI(); switch (uri) { case "/index.html": PushBuilder pushBuilder=httpServletRequest.getPushBuilder(); pushBuilder.path("/styles.css").push(); pushBuilder.path("/logo.png").push(); break; default: break; } chain.doFilter(request, response);; } @Override public void destroy() { } }
框架案例是服务器推送最重要的用例之一,它完全依赖于服务器事先知道客户在客户请求之前要求的资源,服务器web框架可以充分利用服务器推送的优势
禁用/拒绝服务器推送
客户端可以通过发送SETTINGS_ENABLE_PUSH设置值0(零)来显式禁用服务器推送。
除了允许客户端使用SETTINGS_ENABLE_PUSH设置禁用服务器推送之外,servlet容器还必须尊重客户端的请求,以便不通过引用推送流的流标识符的CANCEL或REFUSED_STREAM代码在更细粒度的基础上接收推送的响应。这种交互的一个常见用途是浏览器在其缓存中已有资源时。