Java中间件在进行网络通信时,经常会使用Http协议来发送和接受请求。而我们最常用的就是HttpClient+Jetty服务器配套使用。

Jetty的好处想必已经知道,轻量级,高并发,性能优良,关键是它可以嵌入代码中。非常的方便,适合Java中间件的使用场景。

而HttpClient也同样优秀。不管是发送Get还是Post请求,以及对请求的参数的解析和响应。都十分简便高效。

下面我就将 HttpClient+Jetty 的一些使用经验传授给大家。

一、要用到的Jar包。

SpringBoot 中间件设计和开发 中间件jetty_服务器

二、Jetty服务器接收请求部分。

public class JettyReceive extends AbstractHandler {

	@Override
	public void handle(String url, Request baseRequest, HttpServletRequest request, HttpServletResponse response) {
		// 验证url是否合法
		try {
			String[] tp = url.split("/");
			if (tp.length < 2) {
				try {
					response.sendError(404);
					return;
				} catch (Exception e) {
					e.printStackTrace();
				}
			}

			// 验证请求ip是否在白名单之内(ip过滤)

			// 判断请求类型,并进行对应操作,注意最好放到其他类中进行,以提高响应速度。
			switch (tp[2]) {
			case "test":
				try {
					System.out.println(url);
					System.out.println(getIpAdrress(request));
					System.out.println(getBodyDate(request));
					out(response, "ok");
				} catch (Exception e) {
					out(response, "error");
					e.printStackTrace();
				}
				break;

			default:
				break;
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void out(HttpServletResponse response, String content) {
		OutputStream ops = null;
		try {
			ops = response.getOutputStream();
			response.setCharacterEncoding("UTF-8");
			ops.write(content.getBytes());
			ops.flush();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (ops != null) {
				try {
					ops.close();
				} catch (Exception e2) {
					e2.printStackTrace();
				}
			}
		}
	}

	// 从请求中获取数据
	public String getBodyDate(HttpServletRequest request) {
		String bodyStr = null;
		BufferedReader br = null;

		try {
			// 设置编码
			request.setCharacterEncoding("UTF-8");
			// 创建输入流
			br = new BufferedReader(new InputStreamReader(request.getInputStream()));
			// 获取body内容
			String line = "";
			StringBuffer buf = new StringBuffer();
			while ((line = br.readLine()) != null) {
				buf.append(line);
			}
			bodyStr = buf.toString();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		return bodyStr;
	}

	/**
	 * 获取request的客户端IP地址
	 * 
	 * @param request
	 * @return
	 */
	private static String getIpAdrress(HttpServletRequest request) {
		String ip = request.getHeader("X-Forwarded-For");

		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}

}
  • Jetty接收的部分分为四个方法,分别是:
  • handle(String, Request, HttpServletRequest, HttpServletResponse) :用来接收请求,验证请求合法性,区分类型...
  • out(HttpServletResponse, String):用来返回请求的响应结果
  • getBodyDate(HttpServletRequest):用来获取Post请求的数据
  • getIpAdrress(HttpServletRequest):用来获取请求的ip地址

三、Jetty服务器启动类。

//jetty的启动类
public class JettyStart {

	public static Server server = null;

	public static void start() {
		if (server == null || server.isStopped()) {
			try {
				JettyReceive handler = new JettyReceive();
				// 创建连接监听器,每个监听器可以监听一个端口
				SelectChannelConnector channelConnector = new SelectChannelConnector();
				// 监听端口
				channelConnector.setPort(12345);
				// 每个请求被accept前允许等待的连接数
				channelConnector.setAcceptQueueSize(100);
				// 同时监听read事件的线程数,调用ServerSocket或ServerSocketChannel中accept方法的线程数,建议这个数字小于或等于可用处理器的2倍。
				channelConnector.setAcceptors(2);
				// 连接最大的空闲时间
				channelConnector.setMaxIdleTime(1000);
				// QueuedThreadPool负责把任务提交到队列,空闲的线程过了一段时间会自动销毁
				QueuedThreadPool pool = new QueuedThreadPool();
				// 最小线程数
				pool.setMinThreads(2);
				// 最大线程数
				pool.setMaxIdleTimeMs(10);
				// ===========以上属性参数均可改为可配置==========
				// 连接监听器数组,可设置多个监听器监听多个端口
				SelectChannelConnector[] connectors = new SelectChannelConnector[1];
				connectors[0] = channelConnector;
				// jetty服务器实例
				server = new Server();
				server.setConnectors(connectors);
				server.setThreadPool(pool);
				server.setHandler(handler);
				server.start();
				System.out.println("jetty start successed");
			} catch (Exception e) {
				System.out.println("jetty start failed");
				e.printStackTrace();
				
			}
		}
	}

}
  • 该类的主要用于启动Jetty服务器。
  • 配置一些jetty服务器所需要的参数。

四、部署jetty的主函数

//启动jetty并保活的主函数
public class Main {
	public static void main(String[] args) throws Exception {
		try {
			JettyStart.start();// 启动jetty服务器
		} catch (Exception e) {
			e.printStackTrace();
		}

		// 全局异常监控
		Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {

			@Override
			public void uncaughtException(Thread t, Throwable e) {
				System.out.println("uncaughtException" + e.getMessage());
				System.exit(-1);
			}
		});

		while (true) {
			// 线程保活
			// ...
			// jetty服务器保活
			JettyStart.start();
		}
	}
}
  • 主函数中添加了对jetty的启动,全局异常监控以及jetty的保活。

五、HttpClient发送请求的工具类

public class SendUtils {

	public static void main(String[] args) {
		String result = executeUrlOfPost("http://127.0.0.1:12345/stalin/test", "{\"name\":\"stalin\"}");
		System.out.println(result);
	}

	// 发送get请求
	public static String executeUrl(String url) {
		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;
		try {
			httpClient = HttpClients.createDefault();
			// 设置连接超时时间,获取连接的超时时间,获取数据的超时时间
			RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000)
					.setConnectionRequestTimeout(5000).setSocketTimeout(5000).build();
			HttpGet httpGet = new HttpGet(url);
			httpGet.setConfig(requestConfig);
			response = httpClient.execute(httpGet);

			if (response.getStatusLine().getStatusCode() != 200) {
				return null;
			}

			HttpEntity entity = response.getEntity();
			if (entity != null) {
				return EntityUtils.toString(entity, "UTF-8");
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (response != null) {
					response.close();
				}
			} catch (Exception e2) {
				e2.printStackTrace();
			}
			try {
				if (httpClient != null) {
					httpClient.close();
				}
			} catch (Exception e3) {
				e3.printStackTrace();
			}
		}
		return null;
	}

	// 发送post请求
	public static String executeUrlOfPost(String url, String data) {
		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;
		try {
			httpClient = HttpClients.createDefault();
			// 设置连接超时时间,获取连接的超时时间,获取数据的超时时间
			RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000)
					.setConnectionRequestTimeout(5000).setSocketTimeout(5000).build();

			HttpPost httpPost = new HttpPost(url);
			httpPost.setConfig(requestConfig);
			httpPost.setEntity(new StringEntity(data, "UTF-8"));

			response = httpClient.execute(httpPost);

			if (response.getStatusLine().getStatusCode() != 200) {
				return null;
			}

			HttpEntity entity = response.getEntity();
			if (entity != null) {
				return EntityUtils.toString(entity, "UTF-8");
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (response != null) {
					response.close();
				}
			} catch (Exception e2) {
				e2.printStackTrace();
			}
			try {
				if (httpClient != null) {
					httpClient.close();
				}
			} catch (Exception e3) {
				e3.printStackTrace();
			}
		}
		return null;
	}

	// 发送post请求并将响应的数据解压缩
	public static String executeUrlOfPostForGzip(String url, String data) {
		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;
		try {
			httpClient = HttpClients.createDefault();
			// 设置连接超时时间,获取连接的超时时间,获取数据的超时时间
			RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000)
					.setConnectionRequestTimeout(5000).setSocketTimeout(5000).build();

			HttpPost httpPost = new HttpPost(url);
			httpPost.setConfig(requestConfig);
			httpPost.setEntity(new StringEntity(data, "UTF-8"));

			response = httpClient.execute(httpPost);

			if (response.getStatusLine().getStatusCode() != 200) {
				return null;
			}

			HttpEntity entity = new GzipDecompressingEntity(response.getEntity());
			if (entity != null) {
				return EntityUtils.toString(entity, "UTF-8");
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (response != null) {
					response.close();
				}
			} catch (Exception e2) {
				e2.printStackTrace();
			}
			try {
				if (httpClient != null) {
					httpClient.close();
				}
			} catch (Exception e3) {
				e3.printStackTrace();
			}
		}
		return null;
	}

}
  • 里面包含三个方法:
  • 发送get请求
  • 发送post请求
  • 发送post请求,并解析响应回来的zip包。(可能你的请求会响应大量数据,通过一个压缩包的形式返回给你)

六、在本机测试:

SpringBoot 中间件设计和开发 中间件jetty_java中间件网络编程_02