diff --git a/src/main/kotlin/cn/tursom/core/HttpRequest.kt b/src/main/kotlin/cn/tursom/core/HttpRequest.kt index f216db0..19c888a 100644 --- a/src/main/kotlin/cn/tursom/core/HttpRequest.kt +++ b/src/main/kotlin/cn/tursom/core/HttpRequest.kt @@ -1,366 +1,170 @@ package cn.tursom.core -import java.io.File -import java.io.InputStreamReader -import java.io.OutputStream +import cn.tursom.core.buffer.ByteBuffer +import cn.tursom.core.buffer.impl.HeapByteBuffer +import java.io.InputStream import java.net.HttpURLConnection import java.net.URL +import java.net.URLConnection import java.net.URLEncoder import java.nio.charset.Charset import java.util.zip.GZIPInputStream -/** - * 向指定URL发送GET方法的请求 - * - * @param url - * 发送请求的URL - * @param param - * 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 - * @return URL 所代表远程资源的响应结果 - * @deprecated - */ -fun sendGet( - url: String, - param: String? = null, - headers: Map<String, String> = mapOf( - Pair("accept", "*/*"), - Pair("connection", "Keep-Alive"), - Pair("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)")) -): String { - val realUrl = URL(if (param != null) { - "$url?$param" - } else { - url - }) - // 打开和URL之间的连接 - val connection = realUrl.openConnection() - // 设置请求属性 - headers.forEach { - connection.addRequestProperty(it.key, it.value) - } - // 建立实际的连接 - connection.connect() - // 获取所有响应头字段 - //val map = connection.headerFields - // 遍历所有的响应头字段 -// for (key in map.keys) { -// println(key + "--->" + map[key]) -// } - // 定义 BufferedReader输入流来读取URL的响应 - return connection.getInputStream().let { - if (connection.contentEncoding?.contains("gzip") == true) { - GZIPInputStream(it) +@Suppress("unused", "MemberVisibilityCanBePrivate") +object HttpRequest { + val defaultHeader = mapOf( + "accept" to "*/*", + "connection" to "Keep-Alive", + "user-agent" to "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)", + "Accept-Encoding" to "gzip, deflate, sdch, br" + ) + + fun URLConnection.getCharset(): Charset { + val contentType = getHeaderField("content-type") + return if (contentType == null) { + Charsets.UTF_8 } else { - it - } - }.readBytes().toUTF8String() -} - -fun sendGet( - url: String, - param: Map<String, String>, - headers: Map<String, String> = mapOf( - Pair("accept", "*/*"), - Pair("connection", "Keep-Alive"), - Pair("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)")) -): String { - val paramSB = StringBuilder() - return sendGet(url, run { - param.forEach { - paramSB.append("${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}&") - } - paramSB.toString() - }, headers) -} - -fun sendGet( - url: String, - outputStream: OutputStream, - param: String? = null, - headers: Map<String, String> = mapOf( - Pair("accept", "*/*"), - Pair("connection", "Keep-Alive"), - Pair("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)")) -) { - val realUrl = URL(if (param != null) { - "$url?$param" - } else { - url - }) - // 打开和URL之间的连接 - val connection = realUrl.openConnection() - // 设置请求属性 - headers.forEach { - connection.addRequestProperty(it.key, it.value) - } - // 建立实际的连接 - connection.connect() - - // 读取URL的响应 - connection.getInputStream().use { - it.copyTo(outputStream) - } -} - -fun sendGet( - url: String, - outputStream: OutputStream, - param: Map<String, String>, - headers: Map<String, String> = mapOf( - Pair("accept", "*/*"), - Pair("connection", "Keep-Alive"), - Pair("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)")) -) { - val paramSB = StringBuilder() - sendGet(url, outputStream, run { - param.forEach { - paramSB.append("${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}&") - } - paramSB.toString() - }, headers) -} - -fun getFile(url: String, filename: String) { - File(filename).outputStream().use { - sendGet(url, it) - } -} - -fun sendHead( - url: String, - param: String, - headers: Map<String, String> = mapOf( - Pair("accept", "*/*"), - Pair("connection", "Keep-Alive"), - Pair("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)")) -): Map<String, List<String>> { - val urlNameString = "$url?$param" - val realUrl = URL(urlNameString) - // 打开和URL之间的连接 - val connection = realUrl.openConnection() as HttpURLConnection - // 设置请求属性 - headers.forEach { - connection.addRequestProperty(it.key, it.value) - } - connection.requestMethod = "HEAD" - // 建立实际的连接 - connection.connect() - // 获取响应头字段 - return connection.headerFields -} - -fun sendHead( - url: String, - param: Map<String, String>, - headers: Map<String, String> = mapOf( - Pair("accept", "*/*"), - Pair("connection", "Keep-Alive"), - Pair("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)")) -): Map<String, List<String>> { - val paramSB = StringBuilder() - return sendHead(url, run { - param.forEach { - paramSB.append("${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}&") - } - paramSB.toString() - }, headers) -} - - -/** - * 向指定 URL 发送POST方法的请求 - * - * @param url - * 发送请求的 URL - * @param data - * 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 - * @return 所代表远程资源的响应结果 - */ -@Throws(Exception::class) -fun sendPost( - url: String, - data: ByteArray, - headers: Map<String, String> = mapOf( - Pair("accept", "*/*"), - Pair("connection", "Keep-Alive"), - Pair("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)")) -): String { - val realUrl = URL(url) - // 打开和URL之间的连接 - val conn = realUrl.openConnection() - // 设置通用的请求属性 - headers.forEach { key, value -> - conn.setRequestProperty(key, value) - } - // 发送POST请求必须设置如下两行,HttpUrlConnection会将请求方法自动设置为POST - conn.doOutput = true - conn.doInput = true - - // 获取URLConnection对象对应的输出流 - conn.outputStream.use { out -> - // 发送请求参数 - out.write(data) - // flush输出流的缓冲 - out.flush() - } - - // 定义BufferedReader输入流来读取URL的响应 - return conn.getInputStream().readBytes().toUTF8String() -} - -@Throws(Exception::class) -fun sendPost( - url: String, - param: Map<String, String>, - headers: Map<String, String> = mapOf( - Pair("accept", "*/*"), - Pair("connection", "Keep-Alive"), - Pair("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)")) -): String { - val sb = StringBuilder() - param.forEach { key, value -> - sb.append("${URLEncoder.encode(key, "utf-8")}=${URLEncoder.encode(value, "utf-8")}&") - } - sb.deleteCharAt(sb.length - 1) - return sendPost(url, sb.toString().toByteArray(), headers) -} - -@Throws(Exception::class) -fun sendPost( - url: String, - outputStream: OutputStream, - param: ByteArray, - headers: Map<String, String> = mapOf( - Pair("accept", "*/*"), - Pair("connection", "Keep-Alive"), - Pair("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)")) -) { - val realUrl = URL(url) - // 打开和URL之间的连接 - val conn = realUrl.openConnection() - // 设置通用的请求属性 - headers.forEach { (key, value) -> - conn.setRequestProperty(key, value) - } - // 发送POST请求必须设置如下两行,HttpUrlConnection会将请求方法自动设置为POST - conn.doOutput = true - conn.doInput = true - - // 获取URLConnection对象对应的输出流 - conn.outputStream.use { out -> - // 发送请求参数 - out.write(param) - // flush输出流的缓冲 - out.flush() - } - - // 读取URL的响应 - conn.getInputStream().copyTo(outputStream) -} - -@Throws(Exception::class) -fun sendPost( - url: String, - outputStream: OutputStream, - param: Map<String, String>, - headers: Map<String, String> = mapOf( - Pair("accept", "*/*"), - Pair("connection", "Keep-Alive"), - Pair("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)")) -) { - val sb = StringBuilder() - param.forEach { (key, value) -> - sb.append("${URLEncoder.encode(key, "utf-8")}=${URLEncoder.encode(value, "utf-8")}&") - } - sb.deleteCharAt(sb.length - 1) - sendPost(url, outputStream, sb.toString().toByteArray(), headers) -} - -@Suppress("MemberVisibilityCanBePrivate") -class HttpRequest( - val url: String, - val param: ByteArray? = null, - val headers: Map<String, String> = mapOf( - Pair("accept", "*/*"), - Pair("connection", "Keep-Alive"), - Pair("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)")) -) { - - constructor( - url: String, - param: Map<String, String>? = null, - headers: Map<String, String> = mapOf( - Pair("accept", "*/*"), - Pair("connection", "Keep-Alive"), - Pair("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)")) - ) : this( - url, - param?.run { - val sb = StringBuilder() - param.forEach { (key, value) -> - sb.append("${URLEncoder.encode(key, "utf-8")}=${URLEncoder.encode(value, "utf-8")}&") + val startIndex = contentType.indexOf("charset=", ignoreCase = true) + 8 + if (startIndex < 0) { + Charsets.UTF_8 + } else { + var endIndex = contentType.indexOf("charset=", startIndex = startIndex, ignoreCase = true) + 8 + if (endIndex < 0) endIndex = contentType.length + Charset.forName(contentType.substring(startIndex, endIndex)) } - sb.deleteCharAt(sb.length - 1) - sb.toString().toByteArray() - }, - headers) + } + } - - var body: String? = null - var head: Map<String, List<String>>? = null - - @Throws(Exception::class) - fun get() { - body = null - head = null - val realUrl = URL(if (param != null) { - "$url?${String(param)}" + fun URLConnection.getRealInputStream(): InputStream { + return if (getHeaderField("content-encoding").contains("gzip", true)) { + GZIPInputStream(inputStream) } else { - url - }) - // 打开和URL之间的连接 - val connection = realUrl.openConnection() as HttpURLConnection - // 设置请求属性 - this.headers.forEach { - connection.addRequestProperty(it.key, it.value) + inputStream } - // 建立实际的连接 - connection.connect() - // 获取响应头字段 - head = connection.headerFields - body = InputStreamReader(connection.inputStream).readText() } - @Throws(Exception::class) - fun post() { - body = null - head = null + fun send( + method: String = "GET", + url: String, + headers: Map<String, String> = defaultHeader, + data: ByteBuffer? = null + ): HttpURLConnection { val realUrl = URL(url) - // 打开和URL之间的连接 - val connection = realUrl.openConnection() as HttpURLConnection + val conn = realUrl.openConnection() as HttpURLConnection + headers.forEach { (key, value) -> + conn.setRequestProperty(key, value) + } + if (data != null) conn.doOutput = true + conn.doInput = true + conn.requestMethod = method - // 设置请求属性 - this.headers.forEach { - connection.addRequestProperty(it.key, it.value) + data?.let { + conn.outputStream.use { out -> + data.writeTo(out) + out.flush() + } } - // 发送POST请求必须设置如下两行,HttpUrlConnection会将请求方法自动设置为POST - connection.doOutput = true - connection.doInput = true - - // 建立实际的连接 - connection.connect() - - // 获取URLConnection对象对应的输出流 - if (param != null) connection.outputStream.use { out -> - // 发送请求参数 - out.write(param) - // flush输出流的缓冲 - out.flush() - } - - // 获取响应头字段 - head = connection.headerFields - body = InputStreamReader(connection.inputStream).readText() + return conn } + + fun getContextStream( + method: String = "GET", + url: String, + headers: Map<String, String> = defaultHeader, + data: ByteBuffer? = null + ): InputStream = send(method, url, headers, data).inputStream + + fun getContext( + method: String = "GET", + url: String, + headers: Map<String, String> = defaultHeader, + data: ByteBuffer? = null + ) = send(method, url, headers, data).getRealInputStream().readBytes() + + fun getContextStr( + method: String = "GET", + url: String, + headers: Map<String, String> = defaultHeader, + data: ByteBuffer? = null + ): String { + val conn = send(method, url, headers, data) + return conn.getRealInputStream().readBytes().toString(conn.getCharset()) + } + + fun send( + method: String = "GET", + url: String, + headers: Map<String, String> = defaultHeader, + data: ByteArray? + ) = send(method, url, headers, data?.let { HeapByteBuffer(data) }) + + fun doGet( + url: String, + param: String? = null, + headers: Map<String, String> = defaultHeader + ): String = getContextStr("GET", if (param != null) { + "$url?$param" + } else { + url + }, headers) + + infix operator fun get(url: String): String = doGet(url, null) + + fun doGet( + url: String, + param: Map<String, String>, + headers: Map<String, String> = defaultHeader + ): String { + val paramSB = StringBuilder() + return doGet(url, run { + param.forEach { + paramSB.append("${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}&") + } + if (paramSB.isNotEmpty()) paramSB.deleteCharAt(paramSB.lastIndex) + paramSB.toString() + }, headers) + } + + + fun doHead( + url: String, + param: String, + headers: Map<String, String> = defaultHeader + ): Map<String, List<String>> = send("HEAD", "$url?$param", headers).headerFields + + fun doHead( + url: String, + param: Map<String, String>, + headers: Map<String, String> = defaultHeader + ): Map<String, List<String>> { + val paramSB = StringBuilder() + return doHead(url, run { + param.forEach { + paramSB.append("${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}&") + } + if (paramSB.isNotEmpty()) paramSB.deleteCharAt(paramSB.lastIndex) + paramSB.toString() + }, headers) + } + + fun doPost( + url: String, + data: ByteArray, + headers: Map<String, String> = defaultHeader + ): String = getContextStr("POST", url, headers, HeapByteBuffer(data)) + + fun doPost( + url: String, + param: Map<String, String>, + headers: Map<String, String> = defaultHeader + ): String { + val sb = StringBuilder() + param.forEach { (key, value) -> + sb.append("${URLEncoder.encode(key, "utf-8")}=${URLEncoder.encode(value, "utf-8")}&") + } + if (sb.isNotEmpty()) sb.deleteCharAt(sb.lastIndex) + return doPost(url, sb.toString().toByteArray(), headers) + } + } \ No newline at end of file