之前在本机研究dropwizard时,本着默认的情况下应该开启gzip压缩,因此在相应的yml配置中开启gzip标记(它本身也是开启的).但是在相应的请求返回中并没有出现相应的gzip标识,在chrome浏览器下的标识信息为如下的响应所示:
从上面的标识来看,在响应头上并没有gzip标识.
然后开始痛苦的处理过程,从浏览器,客户端,服务端,然后最后从网络层逐步处理,最终找到问题的原因及出处.
欢迎来到Flym的程序之家
之前在本机研究dropwizard时,本着默认的情况下应该开启gzip压缩,因此在相应的yml配置中开启gzip标记(它本身也是开启的).但是在相应的请求返回中并没有出现相应的gzip标识,在chrome浏览器下的标识信息为如下的响应所示:
从上面的标识来看,在响应头上并没有gzip标识.
然后开始痛苦的处理过程,从浏览器,客户端,服务端,然后最后从网络层逐步处理,最终找到问题的原因及出处.
前段时间在项目中看到如下的代码:
HttpServletResponse response = (HttpServletResponse)servletResponse; response.setHeader("Transfer-Encoding", "utf8"); filterChain.doFilter(servletRequest, servletResponse);
原意是想对输出的内容进行编码,却用错了响应头,结果这个错误的响应头对后面的客户端程序带来了许多麻烦。这里有必要对这个这块的内容进行详细地了解。
传输数据编码:Transfer-Encoding
数据编码,即表示数据在网络传输当中,使用怎么样的保证方式来保证数据是安全成功地传输处理。可以是分段传输,也可以是不分段,直接使用原数据进行传输。
有效的值为:Trunked和Identity.
传输内容编码:Content-Encoding
内容编码,即整个数据信息是在数据器端经过怎样的编码处理,然后客户端会以怎么的编码来反向处理,以得到原始的内容。这里的内容编码主要是指压缩编码,即服务器端压缩,客户端解压缩。
可以参考的值为:gzip,compress,deflate和identity。
传输内容格式:Content-Type
内容格式,即接收的数据最终是以何种的形式显示在浏览器中。可以是一个图片,还是一段文本,或者是一段html。内容格式额外支持可选参数,charset,即实际内容的字符集。通过字符集,客户端可以对数据进行解编码,以最终显示可以看得懂的文字(而不是一段byte[]或者是乱码)。
3种描述信息,可以由下图来表示(来源于《Http权威指南》):
从上文中,可以看出,实际上原filter中的内容可能是想表达以下的意思:
response.setContentType("text/html;charset=UTF8"); //或者 response.setContentType("application/json;charset=UTF8");
本文转自:http://marlonyao.iteye.com/blog/1005690 原文作者:marlonyao
在经典的nio通讯例子中,通常是这样写的:
if (key.isAcceptable()) { ServerSocketChannel server = (ServerSocketChannel) key.channel(); SocketChannel client = server.accept(); System.out.println("Accepted connection from " + client); client.configureBlocking(false); //开始注册读写事件 SelectionKey clientKey = client.register(selector, SelectionKey.OP_WRITE|SelectionKey.OP_READ); } //开始写 if (key.isWritable()) { // System.out.println("is writable..."); SocketChannel client = (SocketChannel) key.channel(); ByteBuffer buffer = (ByteBuffer) key.attachment(); buffer.flip(); client.write(buffer); buffer.compact(); }
在测试例子中,该例子也能够正常的输出,不过就是有一个现象:
但是如果你这时top用看一下发现服务器进程CPU占用到95%以上,如果取消掉32行的注释,服务器会不断地输出"is writable…",这是为什么呢?让我们来分析当第一个客户端连接上时发生什么情况。
从上面的分析可以看出问题在于我们在没有数据可写时就在socket上注册了OP_WRITE,导致服务器浪费大量CPU资源,解决办法是只有数据可以写时才注册OP_WRITE操作。上面的版本还不只浪费CPU那么简单,它还可能导致潜在的死锁。虽然死锁在我的机器上没有发生,对于这个简单的例子似乎也不大可能发生在别的机器上,但是在对于复杂的情况,比如我写的端口转发工具中就发生了,这还依赖于jdk的实现。
我们有一个项目中用到了多个子项目,即将多个子项目的连接地址整合在一起。在客户部署环境中,有一个主终端,负责接受用户登陆,在登陆时,由用户选择最终要登陆的子系统。当输入登陆信息之后,由主终端负责解析用户名和密码,待验证通过之后,再通过主终端负责将用户信息直接发往子系统并通过子系统接口转入到后台操作界面。整个流程就类似于一个统一授权中心,由主终端负责用户授权和访问,在获得授权之后,就可以直接操作子系统了。
前几天在客户方将数据copy回来并进行分析时,发现在首页显示其它子系统时非常的慢,甚至慢到不能忍受的地步。但这种情况在客户环境中并没有发现。待仔细地查看了数据逻辑处理,发现了后台在列举子系统数据时,首先需要判断当前的子系统是否能够连接,即有一个如下的连接代码:
/** 指定的子系统是否是断开连接的 */ public static boolean isOffline(SubSystem subSystem) { String url = subSystem.getRequestAddress(); try { URL requestURL = new URL(url); HttpURLConnection urlConnection = (HttpURLConnection) requestURL.openConnection(); urlConnection.connect(); urlConnection.disconnect(); return false; } catch(Exception ignore) { return true; } }
就是由于这段代码,导致系统长时间停留在这段处理代码中。发现代码在处理connect时,半天无法响应。由于数据是在客户方copy回来了,所要连接的子系统的ip地址为192.168.1.99,而当前在笔者机器的ip为192.168.0.*,即在连接子系统时会无法连接,但这个连接不到所返回的时间也太长了。
笔者测试了下时间,这段连接不的代码在windows下的异常时间(即开始连接到发生异常的时间)为20秒,而linux下这个时间就长了,达到了180秒,即java要经过180秒才能发现这个连接根本就连接不上。
笔者又在cmd下通过ping,来测试一下连接时间,也是发现连接时间长时间也没有响应。