Apahce httpclient 提供HttpRequestInterceptor和
HttpResponseInterceptor两种拦截器分别处理请求和响应数据,下面讲一下如何对http请求进行拦截并进行签名。
1、第一步创建拦截器对象实现HttpRequestInterceptor接口,并重写process方法
import org.apache.http.HttpException; import org.apache.http.HttpRequest; import org.apache.http.HttpRequestInterceptor; import org.apache.http.protocol.HttpContext; import java.io.IOException; public class SpecialHttpRequestInterceptor implements HttpRequestInterceptor{ @Override public void process(HttpRequest httpRequest, HttpContext httpContext) throws HttpException, IOException { } }
2、获取签名需要的参数:path,method,url params,body,token
1> 首先拿到HttpRequest的封装类对象,HttpRequestWrapper: HttpRequestWrapper httpRequestWrapper = HttpRequestWrapper.class.cast(httpRequest);
PS:为什么转换成HttpRequestWrapper,是因为httpclient build生成InternalHttpClient(非异步)或InternalHttpAsyncClient(异步)对象时,InternalHttpClient或 InternalHttpAsyncClient对象的doExecute(非异步)或execute方法(异步)对HttpRequest对象进行封装,产生HttpRequestWrapper对象。拿到HttpRequestWrapper对象,大致的过程是这样的,具体可以去看一下httpclient的源码。
2>获取path:
- 拿到HttpRequestWrapper对象后,获取URI:URI uri = httpRequestWrapper.getURI();
- 获取Path:String path = uri.getPath();
- 拿到URI后,生成URIBuilder:URIBuilder uriBuilder = new URIBuilder(uri),为什么要生成URIBuilder对象呢,是为了后面我们修改请求的参数
3>获取method:String method = httpRequestWrapper.getMethod();
4>获取HttpRequestWrapper内部封装的HttpRequest对象:HttpRequest originHttpRequest = httpRequestWrapper.getOriginal();
5>如果是post请求或者put请求,获取body(如果有的话)
String body = null; HttpEntity entity = null; if (originHttpRequest instanceof HttpPost) { entity = ((HttpPost) originHttpRequest).getEntity(); } else if (originHttpRequest instanceof HttpPut) { entity = ((HttpPut) originHttpRequest).getEntity(); } if (entity != null) { body = IOUtils.toString(entity.getContent(), CHARSET); }
6>获取token(如果有的话)
String token = null; Header header = originHttpRequest.getLastHeader("Authorization"); if(header != null && StringUtils.isNotEmpty(header.getValue())){ token = header.getValue(); }
7>最后就是用上面拿到的数据算签名并且加到parameters中,重新设置URI
下面是完整的代码:
import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.http.*; import org.apache.http.client.methods.*; import org.apache.http.client.utils.URIBuilder; import org.apache.http.message.BasicNameValuePair; import org.apache.http.protocol.HttpContext; import utils.SignUtil; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; import java.util.*; public class SpecialHttpRequestInterceptor implements HttpRequestInterceptor { private static final String CHARSET = "utf-8"; private static final String APP_ID = "10001"; private static final String SECRET_KEY = "123467"; @Override public void process(HttpRequest httpRequest, HttpContext httpContext) throws IOException { //获取HttpRequest的封装类,用于更改属性 HttpRequestWrapper httpRequestWrapper = HttpRequestWrapper.class.cast(httpRequest); //获取请求方式 String method = httpRequestWrapper.getMethod(); //获取URIBuilder,用来重新设置parameters URI uri = httpRequestWrapper.getURI(); URIBuilder uriBuilder = new URIBuilder(uri); String path = uri.getPath(); //获取封装内部的原始HttpRequest对象 HttpRequest originHttpRequest = httpRequestWrapper.getOriginal(); String token = null; String body = null; //获取header中的token Header header = originHttpRequest.getLastHeader("Authorization"); if (header != null && StringUtils.isNotEmpty(header.getValue())) { token = header.getValue(); } //如果是post或put请求,获取body HttpEntity entity = null; if (originHttpRequest instanceof HttpPost) { entity = ((HttpPost) originHttpRequest).getEntity(); } else if (originHttpRequest instanceof HttpPut) { entity = ((HttpPut) originHttpRequest).getEntity(); } if (entity != null) { body = IOUtils.toString(entity.getContent(), CHARSET); } //生成签名并添加到paramters中 List<NameValuePair> pathParams = sign(path, method, uri, body, token); uriBuilder.setParameters(pathParams); try { httpRequestWrapper.setURI(uriBuilder.build()); } catch (URISyntaxException e) { e.printStackTrace(); } } public List<NameValuePair> sign(String path, String method, URI uri, String body, String token) { Map<String, String> urlMap = handleUri(uri); List<NameValuePair> pathParams = addSign(path, method, urlMap, body, token); return pathParams; } public Map<String, String> handleUri(URI uri) { Map<String, String> urlMap = new HashMap<>(); try { String rawQuery = uri.getRawQuery(); if (StringUtils.isNotEmpty(rawQuery)) { String queryParams = URLDecoder.decode(rawQuery, "utf-8"); String[] params = queryParams.split("&"); for (int i = 0; i < params.length; i++) { String[] paramPair = params[i].split("="); if (paramPair.length == 2) { urlMap.put(String.valueOf(paramPair[0]), String.valueOf(paramPair[1])); } } } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return urlMap; } public List<NameValuePair> addSign(String path, String method, Map<String, String> urlMap, String jsonBody, String token) { List<NameValuePair> pathParams = new ArrayList<>(); String app_id = APP_ID; String timestamp = String.valueOf(System.currentTimeMillis() / 1000); for (String key : urlMap.keySet()) { if ("app_id".equals(key)) { app_id = urlMap.get(key); } else if ("timestamp".equals(key)) { timestamp = urlMap.get(key); } else { pathParams.add(new BasicNameValuePair(key, urlMap.get(key))); } } pathParams.add(new BasicNameValuePair("app_id", app_id)); pathParams.add(new BasicNameValuePair("timestamp", timestamp)); //真正算签名的地方 String sign = SignUtil.produceSign(path, method, token, pathParams, jsonBody, SECRET_KEY); pathParams.add(new BasicNameValuePair("sign", sign)); return pathParams; } }