Java中间件在进行网络通信时,经常会使用Http协议来发送和接受请求。而我们最常用的就是HttpClient+Jetty服务器配套使用。
Jetty的好处想必已经知道,轻量级,高并发,性能优良,关键是它可以嵌入代码中。非常的方便,适合Java中间件的使用场景。
而HttpClient也同样优秀。不管是发送Get还是Post请求,以及对请求的参数的解析和响应。都十分简便高效。
下面我就将 HttpClient+Jetty 的一些使用经验传授给大家。
一、要用到的Jar包。
二、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包。(可能你的请求会响应大量数据,通过一个压缩包的形式返回给你)
六、在本机测试: