|
本人最近通过自己动手处理http请求,对http协议、Jetty以及HttpClient有了更深刻的理解,特在此与大家分享。
此图是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捕获请求
直接上代码
1 package test;
2 import org.eclipse.jetty.server.Request;
3 import org.eclipse.jetty.server.Server;
4 import org.eclipse.jetty.server.handler.AbstractHandler;
5
6 import javax.servlet.ServletException;
7 import javax.servlet.http.HttpServletRequest;
8 import javax.servlet.http.HttpServletResponse;
9
10 public class JettyServer {
11 public static void main(String[] args) {
12 try {
13 // 进行服务器配置
14 Server server = new Server(8888);
15 server.setHandler(new MyHandler());
16 // 启动服务器
17 server.start();
18 server.join();
19 } catch (Exception e) {
20 e.printStackTrace();
21 }
22 }
23 }
24
25 class MyHandler extends AbstractHandler {
26
27 @Override
28 public void handle(String target, Request baseRequest,
29 HttpServletRequest request, HttpServletResponse response)
30 throws IOException, ServletException {
31 //写自己的处理
32 }
33
34 }
View Code 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);
}
View Code 2、用HttpClient转发请求
把捕获的请求进行重新组装之后,就可以通过HttpClient转发出去。
HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包。多说无益,简单语法请自行百度。
下面是一个完整的加入了HttpClient进行请求转发的类
1 package service;
2 import java.io.BufferedReader;
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.InputStreamReader;
6 import java.io.UnsupportedEncodingException;
7 import java.util.ArrayList;
8 import java.util.Enumeration;
9 import java.util.List;
10
11 import javax.servlet.http.HttpServletRequest;
12
13 import org.apache.http.Header;
14 import org.apache.http.HttpEntity;
15 import org.apache.http.HttpResponse;
16 import org.apache.http.NameValuePair;
17 import org.apache.http.client.ClientProtocolException;
18 import org.apache.http.client.HttpClient;
19 import org.apache.http.client.entity.UrlEncodedFormEntity;
20 import org.apache.http.client.methods.HttpGet;
21 import org.apache.http.client.methods.HttpPost;
22 import org.apache.http.client.methods.HttpUriRequest;
23 import org.apache.http.impl.client.DefaultHttpClient;
24 import org.apache.http.message.BasicHeader;
25 import org.apache.http.message.BasicNameValuePair;
26
27 public class RequestSender implements Runnable {
28 private HttpClient httpclient = null;
29 private RequestAdaptor requestAdaptor = null;//封装之后的请求
30 private String ip = null;
31 private String port = null;
32
33 public RequestSender(RequestAdaptor requestAdaptor, String ip, String port) {
34 httpclient = new DefaultHttpClient();
35 this.requestAdaptor = requestAdaptor;
36 this.ip = ip;
37 this.port = port;
38 }
39
40 @Override
41 public void run() {
42 send();
43 }
44
45 public void send() {
46 if(requestAdaptor == null) {
47 return;
48 }
49 String method = requestAdaptor.getMethod();
50 String uri = requestAdaptor.getUri();
51 String host = ip + ":" + port;
52 String url = "http://" + host + uri;
53 if(method.equals("GET")) {
54 get(url);
55 }else if(method.equals("POST")) {
56 post(url);
57 }
58 }
59
60 public void get(String url) {
61 url = url + "?" + requestAdaptor.getQueryString();
62 HttpGet httpGet = new HttpGet(url);
63 addHeaders(httpGet);
64 try{
65
66 HttpResponse resp = httpclient.execute(httpGet);
67 System.out.println(resp.getStatusLine().getStatusCode());
68 }catch(ClientProtocolException cp) {
69 cp.printStackTrace();
70 }catch(IOException io) {
71 io.printStackTrace();
72 }
73 //return showResponse(httpGet);
74 }
75
76 public void post(String url) {
77 System.out.println(url);
78 HttpPost httpPost = new HttpPost(url);
79 addHeaders(httpPost);
80 UrlEncodedFormEntity uefEntity = null;
81 try {
82 uefEntity = new UrlEncodedFormEntity(requestAdaptor.getParamList(), "UTF-8");
83 } catch (UnsupportedEncodingException e) {
84 e.printStackTrace();
85 }
86 httpPost.setEntity(uefEntity);
87 try{
88 HttpResponse resp = httpclient.execute(httpPost);
89 System.out.println(resp.getStatusLine().getStatusCode());
90 }catch(ClientProtocolException cp) {
91 cp.printStackTrace();
92 }catch(IOException io) {
93 io.printStackTrace();
94 }
95 //return showResponse(httpPost);
96 }
97
98 public void addHeaders(HttpUriRequest httpUriRequest) {
99 List<Header> headers = requestAdaptor.getHeaders();
100 for(int i = 0 ; i< headers.size();i++){
101 httpUriRequest.addHeader(headers.get(i));
102 }
103 }
104
105 public String showResponse(HttpUriRequest httpUriRequest) {
106 HttpResponse response = null;
107 try {
108 response = httpclient.execute(httpUriRequest);
109 } catch (ClientProtocolException e) {
110 e.printStackTrace();
111 } catch (IOException e) {
112 e.printStackTrace();
113 }
114 HttpEntity entity = response.getEntity();
115 if (entity != null) {
116 InputStream instreams = null;
117 try {
118 instreams = entity.getContent();
119 } catch (UnsupportedOperationException e) {
120 e.printStackTrace();
121 } catch (IOException e) {
122 e.printStackTrace();
123 }
124 String str = convertStreamToString(instreams);
125 //System.out.println(str);
126 // Do not need the rest
127 httpUriRequest.abort();
128 return str;
129 }
130 return null;
131 }
132
133
134 public static String convertStreamToString(InputStream is) {
135 BufferedReader reader = new BufferedReader(new InputStreamReader(is));
136 StringBuilder sb = new StringBuilder();
137 String line = null;
138 try {
139 while ((line = reader.readLine()) != null) {
140 sb.append(line + "\n");
141 }
142 } catch (IOException e) {
143 e.printStackTrace();
144 } finally {
145 try {
146 is.close();
147 } catch (IOException e) {
148 e.printStackTrace();
149 }
150 }
151 return sb.toString();
152 }
153 }
View Code 转发的核心是httpclient.execute(httpGet)和httpclient.execute(httpPost)
转发post请求的时候,需要把参数一个一个的组装进去;而转发get请求的时候就不用,应为参数已经跟在URL后面。但是,无论get还是post,都需要把请求头原封不动的组装进去。
基于以上两点,我们可以做的事情就有很多了。 |
|
|