
com.github.jchanghong.http.HttpHelper.kt Maven / Gradle / Ivy
package com.github.jchanghong.http
import cn.hutool.core.collection.ConcurrentHashSet
import cn.hutool.core.io.FileUtil
import cn.hutool.core.thread.ThreadUtil
import cn.hutool.core.util.CharsetUtil
import cn.hutool.crypto.SecureUtil
import cn.hutool.http.HttpUtil
import cn.hutool.json.JSONUtil
import cn.hutool.system.SystemUtil
import com.github.jchanghong.gson.jsonToObject
import com.github.jchanghong.gson.toJsonStr
import com.github.jchanghong.kotlin.isNotNUllOrBlank2
import com.google.common.net.HttpHeaders
import com.google.common.net.MediaType
import okhttp3.*
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.File
import java.io.IOException
import java.security.SecureRandom
import java.security.cert.X509Certificate
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean
import javax.net.ssl.*
/** okhttp*/
object HttpHelper {
var debug = false
/** 单点登录url路径 ,比如/portal/cas/loginPage*/
var pviaLoginUrlPath = "/portal/cas/loginPage"
/** 运管登录路径,比如/center/login*/
var pviaLoginUrlPathCenter = "/center/login"
/** 比如https://1.1.1.2*/
var pviaIpAndPort = "https://1.1.1.2"
/** http://1.1.1.2:8001*/
var pviaIpAndPortCenter = "http://1.1.1.2:8001"
/** pvia 密码*/
var pviaPassword = "123456"
/** 运管密码*/
var pviaCenterPassword = "123456"
fun info(i: Any): Unit {
if (debug) {
println(i)
}
}
private val client: OkHttpClient
private val pviaisLogin = AtomicBoolean(false)
private val pviaCenterisLogin = AtomicBoolean(false)
private class TrustAllCerts : X509TrustManager {
override fun checkClientTrusted(chain: Array, authType: String?) {
// info(authType+chain.firstOrNull().toString())
}
override fun checkServerTrusted(chain: Array, authType: String?) {
// info(authType+chain.firstOrNull().toString())
}
override fun getAcceptedIssuers(): Array {
return arrayOf()
}
}
private class TrustAllHostnameVerifier : HostnameVerifier {
override fun verify(hostname: String?, session: SSLSession?): Boolean {
// info(hostname + session.toString())
return true
}
}
private fun createSSLSocketFactory(): SSLSocketFactory {
val sc: SSLContext = SSLContext.getInstance("TLS")
sc.init(null, arrayOf(TrustAllCerts()), SecureRandom())
return sc.socketFactory
}
val cookieStore = ConcurrentHashMap>()
val cookieVoList = ConcurrentHashSet()
private var csrf_parameterName = ""
private var csrf_headerName = ""
private var csrf_token = ""
private var cSRFRequestHeadXface = Pair("", "")
private var cSRFRequestHeadXcross = Pair("", "")
private var cSRFRequestHeadXbody = Pair("", "")
private var cSRFRequestHeadialarm = Pair("", "")
fun login(user: String, password: String): Boolean {
val formBody = FormBody.Builder()
.add("userName", "admin")
.build()
val response = client.newCall(
Request.Builder().url("${pviaIpAndPort}/portal/login/ajax/postLoginData.do")
.post(formBody).build()
).execute()
val message = response.bodyString()
info(message)
val parseObj1 = JSONUtil.parseObj(message)
val parseObj = parseObj1.getJSONObject("data")
val vcodestr = parseObj.getStr("vCode")
val salt = parseObj.getStr("salt")
val passtmp = SecureUtil.sha256(SecureUtil.sha256(password + salt) + vcodestr)
val formBodyLogin = FormBody.Builder()
.add("userName", user)
.add("password", passtmp)
.add("serviceUrl", """${pviaIpAndPort}/portal/cas/loginPage?service=${pviaIpAndPort}/portal""")
.add("imageCode", "")
.add("codeId", parseObj.getStr("codeId"))
.add("userType", "0")
.add("lang", "zh_CN")
.build()
val response1 = client.newCall(
Request.Builder().url("${pviaIpAndPort}/portal/login/ajax/submit.do")
.post(formBodyLogin).build()
).execute()
val loginMessage = response1.bodyString()
info(loginMessage)
val url2 = JSONUtil.parseObj(loginMessage).getStr("data") ?: ""
return if ("http" in url2) {
val response2 = client.newCall(Request.Builder().url(url2).build()).execute()
response.close()
response1.close()
if (response2.code == 200) {
println("登陆pvia成功 $response2")
response2.close()
true
} else {
response2.close()
false
}
} else {
println("登陆pvia失败")
response.close()
response1.close()
false
}
}
fun requestCSRFRequestHead(
url: String,
nameRegex: String = "_csrf_header",
valueRegex: String = "_csrf"
): Pair {
val response = this.getAsyn(url).get()
val execute4 = response.bodyString()
// println(execute4)
//
//
//
val toRegex1 = """name="${valueRegex}"\s+content="(\S+)"""".toRegex()
val toRegex2 = """name="${nameRegex}"\s+content="(\S+)"""".toRegex()
val v = toRegex1.find(execute4)!!.groupValues[1]
val k = toRegex2.find(execute4)!!.groupValues[1]
info("add csrf header :$k -> $v")
response.close()
return k to v
}
fun ialarmCSRFRequestHead(): Pair {
val response = client.newCall(
Request.Builder()
.url("${pviaIpAndPort}/ialarm-web/search.do")
.build()
).execute()
val execute4 = response.bodyString()
// info(execute4)
//
// 缉查布控
val toRegex1 = """name=_csrf\s+content=([^>]+)""".toRegex()
val toRegex2 = """name=_csrf_header\s+content=([^>]+)""".toRegex()
val v = toRegex1.find(execute4)!!.groupValues[1]
val k = toRegex2.find(execute4)!!.groupValues[1]
info("add ilarm csrf :$k -> $v")
response.close()
return k to v
}
init {
val cookieDirectory = File("okhttpCacheResponseTmp${System.getProperty(SystemUtil.FILE_SEPARATOR)}cookie.json")
if (!cookieDirectory.exists()) {
FileUtil.touch(cookieDirectory)
println(cookieDirectory.absolutePath)
} else {
println(cookieDirectory.absolutePath)
cookieVoList.addAll(cookieDirectory.readText().jsonToObject>() ?: emptySet())
val map = cookieVoList.mapNotNull { Cookie.parse(it.url.toHttpUrl(), it.setCookie) }
.groupBy { it.domain }.mapValues { ConcurrentHashMap(it.value.associateBy { it.name }) }
cookieStore.putAll(map)
if (cookieVoList.isNotEmpty()) {
val orNull = cookieVoList.firstOrNull { it.csrf_headerName.isNotBlank() }
csrf_headerName = orNull?.csrf_headerName ?: ""
csrf_token = orNull?.csrf_token ?: ""
csrf_parameterName = orNull?.csrf_parameterName ?: ""
}
println("加载文件中cookie " + cookieVoList.toJsonStr())
}
val builder = OkHttpClient.Builder()
.followRedirects(true)
.followSslRedirects(true)
.retryOnConnectionFailure(false)
.addInterceptor { chain ->
val oldRequest = chain.request()
info("用户请求===========" + oldRequest)
if (cSRFRequestHeadXcross.first.isNotBlank() && oldRequest.needCarCsrf()) {
val proceed = chain.proceed(
oldRequest.newBuilder().addHeader(cSRFRequestHeadXcross.first, cSRFRequestHeadXcross.second)
.build()
)
return@addInterceptor proceed
} else if (cSRFRequestHeadXface.first.isNotBlank() && oldRequest.needFaceCsrf()) {
val proceed = chain.proceed(
oldRequest.newBuilder().addHeader(cSRFRequestHeadXface.first, cSRFRequestHeadXface.second)
.build()
)
return@addInterceptor proceed
} else if (cSRFRequestHeadXbody.first.isNotBlank() && oldRequest.needBodyCsrf()) {
val proceed = chain.proceed(
oldRequest.newBuilder().addHeader(cSRFRequestHeadXbody.first, cSRFRequestHeadXbody.second)
.build()
)
return@addInterceptor proceed
} else if (cSRFRequestHeadialarm.first.isNotBlank() && oldRequest.needAlarmCsrf()) {
val proceed = chain.proceed(
oldRequest.newBuilder().addHeader(cSRFRequestHeadialarm.first, cSRFRequestHeadialarm.second)
.build()
)
return@addInterceptor proceed
}
//
// if (cSRFRequestHeadXface.first.isBlank() && oldRequest.needFaceCsrf()) {
//// xface自动增加csrf请求头
// val head = requestCSRFRequestHead("${pviaIpAndPort}/iface-web/index.do")
// cSRFRequestHeadXface=head
// val proceed = chain.proceed(oldRequest.newBuilder().addHeader(head.first, head.second).build())
// return@addInterceptor proceed
// } else if (cSRFRequestHeadXcross.first.isBlank() && oldRequest.needCarCsrf()) {
//// xface自动增加csrf请求头
// val head = requestCSRFRequestHead("${pviaIpAndPort}/ivehicle-web/view/index.do")
// cSRFRequestHeadXcross=head
// val proceed = chain.proceed(oldRequest.newBuilder().addHeader(head.first, head.second).build())
// return@addInterceptor proceed
// } else if (cSRFRequestHeadXbody.first.isBlank() && oldRequest.needBodyCsrf()) {
//// xface自动增加csrf请求头
// val head = requestCSRFRequestHead("https://${pviaIpAndPort}/ibody-web/web/statistic/jumpToStatisticPage.do")
// cSRFRequestHeadXbody=head
// val proceed = chain.proceed(oldRequest.newBuilder().addHeader(head.first, head.second).build())
// return@addInterceptor proceed
// } else if (cSRFRequestHeadialarm.first.isBlank() && oldRequest.needAlarmCsrf()) {
//// xface自动增加csrf请求头
// val head = ialarmCSRFRequestHead()
// cSRFRequestHeadialarm=head
// val proceed = chain.proceed(oldRequest.newBuilder().addHeader(head.first, head.second).build())
// return@addInterceptor proceed
// }
//
val response = chain.proceed(oldRequest)
if (pviaLoginUrlPath in response.request.url.toString()) {
// 跳到cas登录页面,需要登录
val body = response.bodyString()
val regex = """enableCsrf\s+\=\s+JSON.parse\('([^']+)'\)""".toRegex()
val get = regex.find(body)!!.groupValues!![1]
info(get)
// {"token":"7Reae4fy-BTLJ_QoGKxkpykAyyus6E4aVA6U","parameterName":"_csrf","headerName":"X-CSRF-TOKEN"}
val jsonObject = JSONUtil.parseObj(get)
csrf_headerName = jsonObject.getStr("headerName")
csrf_parameterName = jsonObject.getStr("parameterName")
csrf_token = jsonObject.getStr("token")
login("admin", pviaPassword)
response.close()
chain.proceed(oldRequest)
} else if (pviaLoginUrlPathCenter in response.request.url.toString()) {
// 跳到cas登录页面,需要登录
val body = response.bodyString()
val message =
getAsyn("${pviaIpAndPortCenter}/center/api/session?userId=sysadmin").get().bodyString()
info("${pviaIpAndPortCenter}/center/api/session?userId=sysadmin " + message)
val jsonObject = JSONUtil.parseObj(message)
val password = SecureUtil.sha256(
SecureUtil.sha256(pviaCenterPassword + jsonObject.getByPath("data.salt"))
+ jsonObject.getByPath("data.challenge.code")
)
val response1 = postJsonStringAsyn(
"${pviaIpAndPortCenter}/center/api/session", """
{"user":{"id":"sysadmin"},"password":"${password}",
"captcha":"","salt":"${jsonObject.getByPath("data.salt")}",
"challenge":{"code":"${jsonObject.getByPath("data.challenge.code")}",
"id":"${jsonObject.getByPath("data.challenge.id")}"}}
""".trimIndent()
).get()
val headers = response1.headers("refresh-url").firstOrNull() ?: ""
response1.close()
if (headers.isNotBlank()) {
val response2 = getAsyn(headers).get()
response2.close()
println("登录运管成功" + response2)
}
response.close()
chain.proceed(oldRequest)
} else if (response.code == 403 && oldRequest.needFaceCsrf()) {
// xface自动增加csrf请求头
val head = requestCSRFRequestHead("${pviaIpAndPort}/iface-web/index.do")
cSRFRequestHeadXface = head
response.bodyString()
response.close()
val proceed = chain.proceed(oldRequest.newBuilder().addHeader(head.first, head.second).build())
proceed
} else if (response.code == 403 && oldRequest.needCarCsrf()) {
// xface自动增加csrf请求头
val head = requestCSRFRequestHead("${pviaIpAndPort}/ivehicle-web/view/index.do")
cSRFRequestHeadXcross = head
response.bodyString()
response.close()
val proceed = chain.proceed(oldRequest.newBuilder().addHeader(head.first, head.second).build())
proceed
} else if (response.code == 403 && oldRequest.needBodyCsrf()) {
// xface自动增加csrf请求头
val head = requestCSRFRequestHead("${pviaIpAndPort}/ibody-web/web/statistic/jumpToStatisticPage.do")
cSRFRequestHeadXbody = head
response.bodyString()
response.close()
val proceed = chain.proceed(oldRequest.newBuilder().addHeader(head.first, head.second).build())
proceed
} else if (response.code == 403 && oldRequest.needAlarmCsrf()) {
// xface自动增加csrf请求头
val head = ialarmCSRFRequestHead()
cSRFRequestHeadialarm = head
response.bodyString()
response.close()
val proceed = chain.proceed(oldRequest.newBuilder().addHeader(head.first, head.second).build())
proceed
} else {
response
}
}
.addNetworkInterceptor { chain ->
val oldRequest = chain.request()
val names = oldRequest.headers.names()
val requestBuild = oldRequest.newBuilder()
if (csrf_headerName.isNotBlank() && csrf_token.isNotBlank() && csrf_headerName !in names) {
requestBuild.addHeader(csrf_headerName, csrf_token)
}
if (csrf_parameterName.isNotBlank() && csrf_token.isNotBlank() && csrf_parameterName !in names) {
requestBuild.addHeader(csrf_parameterName, csrf_token)
}
val request = requestBuild.build()
val response = chain.proceed(request)
if (response.header(HttpHeaders.SET_COOKIE, "").isNotNUllOrBlank2()) {
cookieVoList.add(
SetCookieBO(
request.url.toString(),
response.header(HttpHeaders.SET_COOKIE, "").toString(),
csrf_headerName,
csrf_token,
csrf_parameterName
)
)
}
info("服务器返回:$response")
response
}
.cookieJar(object : CookieJar {
override fun saveFromResponse(url: HttpUrl, cookies: List) {
for (cookie in cookies) {
val hashMap = cookieStore.getOrPut(cookie.domain) { ConcurrentHashMap() }
hashMap[cookie.name] = cookie
}
// info("cookieJar saveFromResponse ${url.host}" + cookies.joinToString { it.name + it.value })
if (cookieDirectory.exists()) {
FileUtil.writeUtf8String(cookieVoList.toJsonStr(), cookieDirectory)
}
}
override fun loadForRequest(url: HttpUrl): List {
val hashMap = cookieStore.getOrPut(url.host) { ConcurrentHashMap() }
// info("cookieJar loadForRequest ${url.host}:${hashMap.values}")
return hashMap.values.toList()
}
})
.sslSocketFactory(createSSLSocketFactory(), TrustAllCerts())
.hostnameVerifier(TrustAllHostnameVerifier())
.dispatcher(
Dispatcher(
executorService = Executors.newFixedThreadPool(
64,
ThreadUtil.newNamedThreadFactory("OKHttpDispatcher", false)
)
).apply {
this.maxRequests = 64
this.maxRequestsPerHost = 63
})
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(0, TimeUnit.SECONDS)
.readTimeout(0, TimeUnit.SECONDS)
.callTimeout(0, TimeUnit.SECONDS)
kotlin.runCatching {
val cacheDirectory = File(".${System.getProperty(SystemUtil.FILE_SEPARATOR)}okhttpCacheResponseTmp")
FileUtil.mkdir(cacheDirectory)
builder.cache(
Cache(
directory = cacheDirectory,
maxSize = 10L * 1024L * 1024L // 1 MiB
)
)
}
client = builder.build()
}
fun getAsyn(url: String, callback: Callback, headers: Map? = null) {
val request = Request.Builder()
.url(url)
.addHeaders(headers)
.build()
client.newCall(request).enqueue(callback)
}
fun getAsyn(url: String, headers: Map? = null): CompletableFuture {
val future = CompletableFuture()
val request = Request.Builder()
.url(url)
.addHeaders(headers)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
future.completeExceptionally(e)
}
override fun onResponse(call: Call, response: Response) {
future.complete(response)
}
})
return future
}
fun getAsynWithForm(
url: String,
form: Map,
headers: Map? = null
): CompletableFuture {
val future = CompletableFuture()
val request = Request.Builder()
.url(HttpUtil.urlWithForm(url, form, CharsetUtil.CHARSET_UTF_8, true))
.addHeaders(headers)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
future.completeExceptionally(e)
}
override fun onResponse(call: Call, response: Response) {
future.complete(response)
}
})
return future
}
// fun getSyn(url: String, headers: Map? = null): Response {
// val request = Request.Builder()
// .url(url)
// .addHeaders(headers)
// .build()
// return client.newCall(request).execute()
// }
fun postFileAsyn(
url: String,
file: File,
mediaType: MediaType? = null,
headers: Map? = null
): CompletableFuture {
val future = CompletableFuture()
val request = Request.Builder()
.url(url)
.post(file.asRequestBody(mediaType?.toString()?.toMediaType()))
.addHeaders(headers)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
future.completeExceptionally(e)
}
override fun onResponse(call: Call, response: Response) {
future.complete(response)
}
})
return future
}
fun postFormAsyn(
url: String,
form: Map,
headers: Map? = null
): CompletableFuture {
val future = CompletableFuture()
val formbuilder = FormBody.Builder()
for ((k, v) in form) {
formbuilder.add(k, v)
}
val formBody = formbuilder.build()
val request = Request.Builder()
.url(url)
.post(formBody)
.addHeaders(headers)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
future.completeExceptionally(e)
}
override fun onResponse(call: Call, response: Response) {
future.complete(response)
}
})
return future
}
fun postStringAsyn(
url: String,
postBody: String,
mediaType: MediaType? = null,
headers: Map? = null
): CompletableFuture {
val future = CompletableFuture()
val request = Request.Builder()
.url(url)
.post(postBody.toRequestBody((mediaType ?: MediaType.PLAIN_TEXT_UTF_8).toString().toMediaType()))
.addHeaders(headers)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
future.completeExceptionally(e)
}
override fun onResponse(call: Call, response: Response) {
future.complete(response)
}
})
return future
}
fun postJsonStringAsyn(
url: String,
jsonBody: String,
headers: Map? = null,
form: Map? = null
): CompletableFuture {
val future = CompletableFuture()
val urls = if (form.isNullOrEmpty()) url else HttpUtil.urlWithForm(url, form, CharsetUtil.CHARSET_UTF_8, true)
val request = Request.Builder()
.url(urls)
.post(jsonBody.toRequestBody(MediaType.JSON_UTF_8.toString().toMediaType()))
.addHeaders(headers)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
future.completeExceptionally(e)
}
override fun onResponse(call: Call, response: Response) {
future.complete(response)
}
})
return future
}
/** form 可以是string 和file类型*/
fun postMultipartAsyn(
url: String,
form: Map,
headers: Map? = null
): CompletableFuture {
// val IMGUR_CLIENT_ID = "9199fdef135c122"
val future = CompletableFuture()
// Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image
val builder = MultipartBody.Builder()
.setType(MultipartBody.FORM)
for ((k, v) in form) {
val file = v as? File
if (file == null) {
builder.addFormDataPart(k, v.toString())
} else {
builder.addFormDataPart(k, file.name, file.asRequestBody())
}
}
val requestBody = builder
// .addFormDataPart("title", "Square Logo")
// .addFormDataPart("image", "logo-square.png",
// File("docs/images/logo-square.png").asRequestBody(PostMultipart.MEDIA_TYPE_PNG))
.build()
val request = Request.Builder()
// .header("Authorization", "Client-ID ${PostMultipart.IMGUR_CLIENT_ID}")
.url(url)
.post(requestBody)
.addHeaders(headers)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
future.completeExceptionally(e)
}
override fun onResponse(call: Call, response: Response) {
future.complete(response)
}
})
return future
}
}
fun Request.Builder.addHeaders(headers: Map?): Request.Builder {
headers ?: return this
for ((k, v) in headers.entries) {
this.addHeader(k, v)
}
return this
}
/** 调用close*/
fun Response.bodyString(): String {
val s = this.body?.string() ?: ""
this.close()
return s
}
fun Request.needFaceCsrf(): Boolean {
return ("/iface-web" in url.toString()) && ("iface-web/index.do" !in url.toString())
}
fun Request.needCarCsrf(): Boolean {
return ("/ivehicle-web" in url.toString()) && ("/ivehicle-web/view/index.do" !in url.toString())
}
fun Request.needBodyCsrf(): Boolean {
return ("/ibody-web" in url.toString()) && ("web/statistic/jumpToStatisticPage.do" !in url.toString())
}
fun Request.needAlarmCsrf(): Boolean {
return ("/ialarm-we" in url.toString()) && ("ialarm-web/search.do" !in url.toString())
}
data class SetCookieBO(
var url: String,
var setCookie: String,
var csrf_headerName: String,
var csrf_token: String,
var csrf_parameterName: String
)
fun main() {
println(
HttpUtil.encodeParams(
HttpUtil.urlWithForm(
"http://www.baidu.com/是",
mapOf("ss" to "s飒飒 1"),
CharsetUtil.CHARSET_UTF_8,
true
), CharsetUtil.CHARSET_UTF_8
)
)
println(HttpUtil.urlWithForm("http://www.baidu.com/是", mapOf("ss" to "s飒飒 1"), CharsetUtil.CHARSET_UTF_8, true))
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy