leftso 5722 0 2018-04-03 21:12:28

前言

Java EE的下一个版本将是版本8,当它最终发布时,我们将在现有的API中看到一些非常有趣的改进。其中一项改进是将HTTP / 2应用于Servlet技术。

适当的抽象

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.cssjavaScript_1.js  文件,所以我们从HTTP请求中获取PushBuilder,并将路径设置为style_1.css文件并调用push,然后将路径设置为javaScript_1。 js文件并再次调用推送。

http2执行流程
注意在这种情况下,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() {

	}

}

JSF用例

框架案例是服务器推送最重要的用例之一。它完全依赖于服务器事先知道客户在客户请求之前要求的资源。服务器端Web框架可以充分利用服务器推送的优势。

所以JSF可以很容易地使用服务器推送。所以每当JSF要呈现样式表时,例如,它将调用encodeResourceURL方法,这是入口点,在这里我们可以初始化服务器推送的调用。

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ExternalContextImp extends ExternalContext{

	@Override
	public String encodeResourceURL(String url) {
		//...
		((HttpServletRequest)request).getPushBuilder().path(url).push();
		//...
		return ((HttpServletResponse)response).encodeURL(url);
	}
}

这就是Web框架的工作原理,就像JSF将能够利用服务器推送修改一样。这还没有实现,我们将看看他们是如何决定这么做的,或者他们是否想出了另一种方法。

禁用/拒绝服务器推送

客户端可以通过发送SETTINGS_ENABLE_PUSH设置值0(零)来显式禁用服务器推送。

除了允许客户端使用SETTINGS_ENABLE_PUSH设置禁用服务器推送之外,servlet容器还必须尊重客户端的请求,以便不通过引用推送流的流标识符的CANCELREFUSED_STREAM代码在更细粒度的基础上接收推送的响应。这种交互的一个常见用途是浏览器在其缓存中已有资源时。

 

编程技术 servlet4 java