Jetty + HttpClient 处理http请求

时间:2023-03-08 17:43:36

本人最近通过自己动手处理http请求,对http协议、Jetty以及HttpClient有了更深刻的理解,特在此与大家分享。

Jetty + HttpClient 处理http请求

此图是http协议的请求格式。根据请求方法,有get和post之分。get和post的区别在于参数传递的方式:post的参数就是请求包体那一行;get的参数跟在URL后面,也就没有请求包体。

get方式的请求格式

GET /search?hl=zh-CN&source=hp&q=domety&aq=f&oq= HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint,
application/msword, application/x-silverlight, application/x-shockwave-flash, */*
Referer: <a href="http://www.google.cn/">http://www.google.cn/</a>
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; TheWorld)
Host: <a href="http://www.google.cn">www.google.cn</a>
Connection: Keep-Alive
Cookie: PREF=ID=80a06da87be9ae3c:U=f7167333e2c3b714:NW=1:TM=1261551909:LM=1261551917:S=ybYcq2wpfefs4V9g;
NID=31=ojj8d-IygaEtSxLgaJmqSjVhCspkviJrB6omjamNrSm8lZhKy_yMfO2M4QMRKcH1g0iQv9u-2hfBW7bUFwVh7pGaRUb0RnHcJU37y-
FxlRugatx63JLv7CWMD6UB_O_r

post方式的请求格式

POST /search HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint,
application/msword, application/x-silverlight, application/x-shockwave-flash, */*
Referer: <a href="http://www.google.cn/">http://www.google.cn/</a>
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; TheWorld)
Host: <a href="http://www.google.cn">www.google.cn</a>
Connection: Keep-Alive
Cookie: PREF=ID=80a06da87be9ae3c:U=f7167333e2c3b714:NW=1:TM=1261551909:LM=1261551917:S=ybYcq2wpfefs4V9g;
NID=31=ojj8d-IygaEtSxLgaJmqSjVhCspkviJrB6omjamNrSm8lZhKy_yMfO2M4QMRKcH1g0iQv9u-2hfBW7bUFwVh7pGaRUb0RnHcJU37y-
FxlRugatx63JLv7CWMD6UB_O_r hl=zh-CN&source=hp&q=domety

所以,对请求进行解析的时候需要区分。

1、用Jetty捕获请求

直接上代码

 package test;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; public class JettyServer {
public static void main(String[] args) {
try {
// 进行服务器配置
Server server = new Server(8888);
server.setHandler(new MyHandler());
// 启动服务器
server.start();
server.join();
} catch (Exception e) {
e.printStackTrace();
}
}
} class MyHandler extends AbstractHandler { @Override
public void handle(String target, Request baseRequest,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
//写自己的处理
} }

Jetty类似于tomcat,但是Jetty比较轻量级,特别适合内嵌到自己写的程序中,比如Hadoop的内置Server就是Jetty。

Jetty将请求进行了封装,比如Jetty自己的Request类,以及我们熟悉的HttpServletRequest类;并且把对象传递给handler。我们拿到HttpServletRequest的对象,就可以对请求进行解析、修改和拼装

Enumeration params = request.getParameterNames();
while(params.hasMoreElements()){
String paraName = (String)params.nextElement();
String paraValue = request.getParameter(paraName);
paramList.add(new BasicNameValuePair(paraName, paraValue));
} Enumeration headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = (String) headerNames.nextElement();
//HttpClient会自动加上这个请求头
if(headerName.equals("Content-Length")) {
continue;
}
String headerValue = request.getHeader(headerName);
Header header = new BasicHeader(headerName, headerValue);
headers.add(header);
}

2、用HttpClient转发请求

把捕获的请求进行重新组装之后,就可以通过HttpClient转发出去。

HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包。多说无益,简单语法请自行百度。

下面是一个完整的加入了HttpClient进行请求转发的类

 package service;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List; import javax.servlet.http.HttpServletRequest; import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair; public class RequestSender implements Runnable {
private HttpClient httpclient = null;
private RequestAdaptor requestAdaptor = null;//封装之后的请求
private String ip = null;
private String port = null; public RequestSender(RequestAdaptor requestAdaptor, String ip, String port) {
httpclient = new DefaultHttpClient();
this.requestAdaptor = requestAdaptor;
this.ip = ip;
this.port = port;
} @Override
public void run() {
send();
} public void send() {
if(requestAdaptor == null) {
return;
}
String method = requestAdaptor.getMethod();
String uri = requestAdaptor.getUri();
String host = ip + ":" + port;
String url = "http://" + host + uri;
if(method.equals("GET")) {
get(url);
}else if(method.equals("POST")) {
post(url);
}
} public void get(String url) {
url = url + "?" + requestAdaptor.getQueryString();
HttpGet httpGet = new HttpGet(url);
addHeaders(httpGet);
try{ HttpResponse resp = httpclient.execute(httpGet);
System.out.println(resp.getStatusLine().getStatusCode());
}catch(ClientProtocolException cp) {
cp.printStackTrace();
}catch(IOException io) {
io.printStackTrace();
}
//return showResponse(httpGet);
} public void post(String url) {
System.out.println(url);
HttpPost httpPost = new HttpPost(url);
addHeaders(httpPost);
UrlEncodedFormEntity uefEntity = null;
try {
uefEntity = new UrlEncodedFormEntity(requestAdaptor.getParamList(), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
httpPost.setEntity(uefEntity);
try{
HttpResponse resp = httpclient.execute(httpPost);
System.out.println(resp.getStatusLine().getStatusCode());
}catch(ClientProtocolException cp) {
cp.printStackTrace();
}catch(IOException io) {
io.printStackTrace();
}
//return showResponse(httpPost);
} public void addHeaders(HttpUriRequest httpUriRequest) {
List<Header> headers = requestAdaptor.getHeaders();
for(int i = 0 ; i< headers.size();i++){
httpUriRequest.addHeader(headers.get(i));
}
} public String showResponse(HttpUriRequest httpUriRequest) {
HttpResponse response = null;
try {
response = httpclient.execute(httpUriRequest);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instreams = null;
try {
instreams = entity.getContent();
} catch (UnsupportedOperationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
String str = convertStreamToString(instreams);
//System.out.println(str);
// Do not need the rest
httpUriRequest.abort();
return str;
}
return null;
} public static String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
}

转发的核心是httpclient.execute(httpGet)和httpclient.execute(httpPost)

转发post请求的时候,需要把参数一个一个的组装进去;而转发get请求的时候就不用,应为参数已经跟在URL后面。但是,无论get还是post,都需要把请求头原封不动的组装进去。

基于以上两点,我们可以做的事情就有很多了。