Browse Source

add HttpInputStream

Looly 6 years ago
parent
commit
9e39667e5a

+ 1 - 0
CHANGELOG.md

@@ -16,6 +16,7 @@
 * 【core】         强化ExceptionUtil(issue#459@Github)
 * 【core】         增强日期工具类(pr#455@Github)
 * 【setting】      构造Setting增加默认字符编码
+* 【extra】        ServletUtil增加getHeaderMap方法
 
 ### Bug修复
 * 【cache】       修复missCount规则(issue#465@Github)

+ 4 - 4
hutool-core/src/main/java/cn/hutool/core/io/watch/WatchMonitor.java

@@ -55,10 +55,10 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
 	public static final WatchEvent.Kind<?> ENTRY_DELETE = StandardWatchEventKinds.ENTRY_DELETE;
 	/** 全部事件 */
 	public static final WatchEvent.Kind<?>[] EVENTS_ALL = {//
-			StandardWatchEventKinds.OVERFLOW,        //事件丢失
-			StandardWatchEventKinds.ENTRY_MODIFY, //修改
-			StandardWatchEventKinds.ENTRY_CREATE,  //创建
-			StandardWatchEventKinds.ENTRY_DELETE   //删除
+			OVERFLOW,        //事件丢失
+			ENTRY_MODIFY, //修改
+			ENTRY_CREATE,  //创建
+			ENTRY_DELETE   //删除
 	};
 	
 	/** 监听路径,必须为目录 */

+ 45 - 15
hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java

@@ -5,9 +5,9 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
 import java.io.Writer;
 import java.lang.reflect.Type;
+import java.nio.charset.Charset;
 import java.util.Collections;
 import java.util.Date;
 import java.util.Enumeration;
@@ -268,14 +268,35 @@ public class ServletUtil {
 
 	// --------------------------------------------------------- Header start
 	/**
+	 * 获取请求所有的头(header)信息
+	 * 
+	 * @param request 请求对象{@link HttpServletRequest}
+	 * @return header值
+	 * @since 4.6.2
+	 */
+	public static Map<String, String> getHeaderMap(HttpServletRequest request) {
+		final Map<String, String> headerMap = new HashMap<>();
+		
+		final Enumeration<String> names = request.getHeaderNames();
+		String name = null;
+		while (names.hasMoreElements()) {
+			name = names.nextElement();
+			headerMap.put(name, request.getHeader(name));
+		}
+		
+		return headerMap;
+	}
+	
+	
+	/**
 	 * 忽略大小写获得请求header中的信息
 	 * 
 	 * @param request 请求对象{@link HttpServletRequest}
 	 * @param nameIgnoreCase 忽略大小写头信息的KEY
 	 * @return header值
 	 */
-	public final static String getHeaderIgnoreCase(HttpServletRequest request, String nameIgnoreCase) {
-		Enumeration<String> names = request.getHeaderNames();
+	public static String getHeaderIgnoreCase(HttpServletRequest request, String nameIgnoreCase) {
+		final Enumeration<String> names = request.getHeaderNames();
 		String name = null;
 		while (names.hasMoreElements()) {
 			name = names.nextElement();
@@ -286,6 +307,18 @@ public class ServletUtil {
 
 		return null;
 	}
+	
+	/**
+	 * 获得请求header中的信息
+	 * 
+	 * @param request 请求对象{@link HttpServletRequest}
+	 * @param name 头信息的KEY
+	 * @param charsetName 字符集
+	 * @return header值
+	 */
+	public static String getHeader(HttpServletRequest request, String name, String charsetName) {
+		return getHeader(request, name, CharsetUtil.charset(charsetName));
+	}
 
 	/**
 	 * 获得请求header中的信息
@@ -294,15 +327,12 @@ public class ServletUtil {
 	 * @param name 头信息的KEY
 	 * @param charset 字符集
 	 * @return header值
+	 * @since 4.6.2
 	 */
-	public final static String getHeader(HttpServletRequest request, String name, String charset) {
+	public static String getHeader(HttpServletRequest request, String name, Charset charset) {
 		final String header = request.getHeader(name);
 		if (null != header) {
-			try {
-				return new String(header.getBytes(CharsetUtil.ISO_8859_1), charset);
-			} catch (UnsupportedEncodingException e) {
-				throw new UtilException(StrUtil.format("Error charset {} for http request header.", charset));
-			}
+			return CharsetUtil.convert(header, CharsetUtil.CHARSET_ISO_8859_1, charset);
 		}
 		return null;
 	}
@@ -375,7 +405,7 @@ public class ServletUtil {
 	 * @param name cookie名
 	 * @return Cookie对象
 	 */
-	public final static Cookie getCookie(HttpServletRequest httpServletRequest, String name) {
+	public static Cookie getCookie(HttpServletRequest httpServletRequest, String name) {
 		final Map<String, Cookie> cookieMap = readCookieMap(httpServletRequest);
 		return cookieMap == null ? null : cookieMap.get(name);
 	}
@@ -386,7 +416,7 @@ public class ServletUtil {
 	 * @param httpServletRequest {@link HttpServletRequest}
 	 * @return Cookie map
 	 */
-	public final static Map<String, Cookie> readCookieMap(HttpServletRequest httpServletRequest) {
+	public static Map<String, Cookie> readCookieMap(HttpServletRequest httpServletRequest) {
 		Map<String, Cookie> cookieMap = new HashMap<String, Cookie>();
 		Cookie[] cookies = httpServletRequest.getCookies();
 		if (null == cookies) {
@@ -404,7 +434,7 @@ public class ServletUtil {
 	 * @param response 响应对象{@link HttpServletResponse}
 	 * @param cookie Servlet Cookie对象
 	 */
-	public final static void addCookie(HttpServletResponse response, Cookie cookie) {
+	public static void addCookie(HttpServletResponse response, Cookie cookie) {
 		response.addCookie(cookie);
 	}
 
@@ -415,7 +445,7 @@ public class ServletUtil {
 	 * @param name Cookie名
 	 * @param value Cookie值
 	 */
-	public final static void addCookie(HttpServletResponse response, String name, String value) {
+	public static void addCookie(HttpServletResponse response, String name, String value) {
 		response.addCookie(new Cookie(name, value));
 	}
 
@@ -429,7 +459,7 @@ public class ServletUtil {
 	 * @param path Cookie的有效路径
 	 * @param domain the domain name within which this cookie is visible; form is according to RFC 2109
 	 */
-	public final static void addCookie(HttpServletResponse response, String name, String value, int maxAgeInSeconds, String path, String domain) {
+	public static void addCookie(HttpServletResponse response, String name, String value, int maxAgeInSeconds, String path, String domain) {
 		Cookie cookie = new Cookie(name, value);
 		if (domain != null) {
 			cookie.setDomain(domain);
@@ -449,7 +479,7 @@ public class ServletUtil {
 	 * @param value cookie值
 	 * @param maxAgeInSeconds -1: 关闭浏览器清除Cookie. 0: 立即清除Cookie. &gt;0 : Cookie存在的秒数.
 	 */
-	public final static void addCookie(HttpServletResponse response, String name, String value, int maxAgeInSeconds) {
+	public static void addCookie(HttpServletResponse response, String name, String value, int maxAgeInSeconds) {
 		addCookie(response, name, value, maxAgeInSeconds, "/", null);
 	}
 

+ 1 - 1
hutool-extra/src/main/java/cn/hutool/extra/tokenizer/engine/analysis/AnalysisEngine.java

@@ -20,7 +20,7 @@ import cn.hutool.extra.tokenizer.TokenizerException;
 public class AnalysisEngine implements TokenizerEngine {
 
 	private Analyzer analyzer;
-	
+
 	/**
 	 * 构造
 	 * 

+ 2 - 2
hutool-extra/src/main/java/cn/hutool/extra/tokenizer/engine/ansj/AnsjEngine.java

@@ -4,8 +4,8 @@ import org.ansj.splitWord.Analysis;
 import org.ansj.splitWord.analysis.ToAnalysis;
 
 import cn.hutool.core.util.StrUtil;
-import cn.hutool.extra.tokenizer.TokenizerEngine;
 import cn.hutool.extra.tokenizer.Result;
+import cn.hutool.extra.tokenizer.TokenizerEngine;
 
 /**
  * Ansj分词引擎实现<br>
@@ -38,5 +38,5 @@ public class AnsjEngine implements TokenizerEngine {
 	public Result parse(CharSequence text) {
 		return new AnsjResult(analysis.parseStr(StrUtil.str(text)));
 	}
-
+	
 }

+ 1 - 1
hutool-extra/src/main/java/cn/hutool/extra/tokenizer/engine/hanlp/HanLPEngine.java

@@ -39,5 +39,5 @@ public class HanLPEngine implements TokenizerEngine {
 	public Result parse(CharSequence text) {
 		return new HanLPResult(this.seg.seg(StrUtil.str(text)));
 	}
-
+	
 }

+ 0 - 1
hutool-extra/src/main/java/cn/hutool/extra/tokenizer/engine/ikanalyzer/IKAnalyzerEngine.java

@@ -39,5 +39,4 @@ public class IKAnalyzerEngine implements TokenizerEngine {
 		this.seg.reset(StrUtil.getReader(text));
 		return new IKAnalyzerResult(this.seg);
 	}
-
 }

+ 111 - 0
hutool-http/src/main/java/cn/hutool/http/HttpInputStream.java

@@ -0,0 +1,111 @@
+package cn.hutool.http;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.DeflaterInputStream;
+import java.util.zip.GZIPInputStream;
+
+import cn.hutool.core.util.StrUtil;
+
+/**
+ * HTTP输入流,此流用于包装Http请求响应内容的流,用于解析各种压缩、分段的响应流内容
+ * 
+ * @author Looly
+ *
+ */
+public class HttpInputStream extends InputStream {
+
+	/** 原始流 */
+	private volatile InputStream in;
+
+	/**
+	 * 构造
+	 * 
+	 * @param response 响应对象
+	 */
+	public HttpInputStream(HttpResponse response) {
+		init(response);
+	}
+
+	@Override
+	public int read() throws IOException {
+		return this.in.read();
+	}
+	
+	@Override
+	public int read(byte[] b, int off, int len) throws IOException {
+		return this.in.read(b, off, len);
+	}
+	
+	@Override
+	public long skip(long n) throws IOException {
+		return this.in.skip(n);
+	}
+	
+	@Override
+	public int available() throws IOException {
+		return this.in.available();
+	}
+	
+	@Override
+	public void close() throws IOException {
+		this.in.close();
+	}
+	
+	@Override
+	public synchronized void mark(int readlimit) {
+		this.in.mark(readlimit);
+	}
+	
+	@Override
+	public synchronized void reset() throws IOException {
+		this.in.reset();
+	}
+	
+	@Override
+	public boolean markSupported() {
+		return this.in.markSupported();
+	}
+
+	/**
+	 * 初始化流
+	 * 
+	 * @param response 响应对象
+	 */
+	private void init(HttpResponse response) {
+		try {
+			this.in = (response.status < HttpStatus.HTTP_BAD_REQUEST) ? response.httpConnection.getInputStream() : response.httpConnection.getErrorStream();
+		} catch (IOException e) {
+			if (e instanceof FileNotFoundException) {
+				// 服务器无返回内容,忽略之
+			} else {
+				throw new HttpException(e);
+			}
+		}
+		
+		// 在一些情况下,返回的流为null,此时提供状态码说明
+		if (null == this.in) {
+			this.in = new ByteArrayInputStream(StrUtil.format("Error request, response status: {}", response.status).getBytes());
+			return;
+		}
+		
+		// TODO 分段响应内容解析
+		if(response.isChunked()) {
+		}
+
+		if (response.isGzip() && false == (response.in instanceof GZIPInputStream)) {
+			// Accept-Encoding: gzip
+			try {
+				this.in = new GZIPInputStream(this.in);
+			} catch (IOException e) {
+				// 在类似于Head等方法中无body返回,此时GZIPInputStream构造会出现错误,在此忽略此错误读取普通数据
+				// ignore
+			}
+		} else if (response.isDeflate() && false == (this.in instanceof DeflaterInputStream)) {
+			// Accept-Encoding: defalte
+			this.in = new DeflaterInputStream(this.in);
+		}
+	}
+}

+ 7 - 25
hutool-http/src/main/java/cn/hutool/http/HttpResponse.java

@@ -12,8 +12,6 @@ import java.net.HttpCookie;
 import java.nio.charset.Charset;
 import java.util.List;
 import java.util.Map.Entry;
-import java.util.zip.DeflaterInputStream;
-import java.util.zip.GZIPInputStream;
 
 import cn.hutool.core.convert.Convert;
 import cn.hutool.core.io.FastByteArrayOutputStream;
@@ -38,13 +36,13 @@ import cn.hutool.log.StaticLog;
 public class HttpResponse extends HttpBase<HttpResponse> implements Closeable {
 
 	/** 持有连接对象 */
-	private HttpConnection httpConnection;
+	protected HttpConnection httpConnection;
 	/** Http请求原始流 */
-	private InputStream in;
+	protected InputStream in;
 	/** 是否异步,异步下只持有流,否则将在初始化时直接读取body内容 */
 	private volatile boolean isAsync;
 	/** 响应状态码 */
-	private int status;
+	protected int status;
 	/** 是否忽略读取Http响应体 */
 	private boolean ignoreBody;
 	/** 从响应中获取的编码 */
@@ -373,9 +371,9 @@ public class HttpResponse extends HttpBase<HttpResponse> implements Closeable {
 	 * @throws HttpException IO异常
 	 */
 	private HttpResponse init() throws HttpException {
+		// 获取响应状态码
 		try {
 			this.status = httpConnection.responseCode();
-			this.in = (this.status < HttpStatus.HTTP_BAD_REQUEST) ? this.httpConnection.getInputStream() : this.httpConnection.getErrorStream();
 		} catch (IOException e) {
 			if (e instanceof FileNotFoundException) {
 				// 服务器无返回内容,忽略之
@@ -394,31 +392,15 @@ public class HttpResponse extends HttpBase<HttpResponse> implements Closeable {
 		// 存储服务端设置的Cookie信息
 		GlobalCookieManager.store(httpConnection);
 
+		// 获取响应编码
 		final Charset charset = httpConnection.getCharset();
 		this.charsetFromResponse = charset;
 		if (null != charset) {
 			this.charset = charset;
 		}
 
-		if (null == this.in) {
-			// 在一些情况下,返回的流为null,此时提供状态码说明
-			this.in = new ByteArrayInputStream(StrUtil.format("Error request, response status: {}", this.status).getBytes());
-		} else {
-			// TODO 分段响应内容解析
-			
-			if (isGzip() && false == (in instanceof GZIPInputStream)) {
-				// Accept-Encoding: gzip
-				try {
-					in = new GZIPInputStream(in);
-				} catch (IOException e) {
-					// 在类似于Head等方法中无body返回,此时GZIPInputStream构造会出现错误,在此忽略此错误读取普通数据
-					// ignore
-				}
-			} else if (isDeflate() && false == (in instanceof DeflaterInputStream)) {
-				// Accept-Encoding: defalte
-				in = new DeflaterInputStream(in);
-			}
-		}
+		// 获取响应内容流
+		this.in = new HttpInputStream(this);
 
 		// 同步情况下强制同步
 		return this.isAsync ? this : forceSync();

+ 2 - 1
hutool-http/src/test/java/cn/hutool/http/test/HttpUtilTest.java

@@ -63,7 +63,8 @@ public class HttpUtilTest {
 	@Test
 	@Ignore
 	public void getTest5() {
-		String res = HttpUtil.get("https://comment.bilibili.com/67573272.xml");
+		String res = HttpRequest.get("https://comment.bilibili.com/67573272.xml")
+				.execute().body();
 		Console.log(res);
 	}