Java/Python解决HTTP(S)主机名解析失败及TLSV1_UNRECOGNIZED_NAME错误
解决方案:访问epic7db.com的TLS与主机名问题
问题核心
目标网站epic7db.com的TLS配置存在特殊处理:程序解析主机名失败,直接用IP访问时触发TLSV1_UNRECOGNIZED_NAME错误,但浏览器可正常访问。这大概率是网站服务器对SNI(Server Name Indication)的校验逻辑异常,或证书与主机名的映射规则特殊。
Python 解决方案
针对requests代码,需要强制指定SNI主机名,同时确保请求头包含正确的Host字段,可通过自定义SSLAdapter实现:
import requests from requests.adapters import HTTPAdapter from urllib3.poolmanager import PoolManager import ssl class SNIAdapter(HTTPAdapter): def init_poolmanager(self, connections, maxsize, block=False): self.poolmanager = PoolManager( num_pools=connections, maxsize=maxsize, block=block, ssl_version=ssl.PROTOCOL_TLS_CLIENT, server_hostname="epic7db.com" # 强制指定SNI主机名 ) headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36', 'Host': 'epic7db.com' # 显式设置Host头 } url = 'https://epic7db.com' session = requests.Session() session.mount('https://', SNIAdapter()) try: response = session.get(url, headers=headers) response.raise_for_status() print(response.content) except Exception as e: print(f"错误: {e}")
若直接用IP访问,需保持Host头和SNI主机名一致:
url = 'https://157.230.84.20/heroes' headers['Host'] = 'epic7db.com' # 其余代码同上,SNIAdapter仍指定server_hostname为epic7db.com
Java/Kotlin 解决方案
你尝试清空SNI列表无效,可能是Java SSL上下文默认仍会自动添加SNI。可尝试以下两种方案:
方案1:强制设置正确的SNI主机名
取消注释SNI添加逻辑,确保SSL参数正确传递:
import java.net.URL import javax.net.ssl.* fun main() { // 信任所有证书(仅测试用,生产环境请勿使用) val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager { override fun checkClientTrusted(chain: Array<java.security.cert.X509Certificate>?, authType: String?) {} override fun checkServerTrusted(chain: Array<java.security.cert.X509Certificate>?, authType: String?) {} override fun getAcceptedIssuers(): Array<java.security.cert.X509Certificate> = arrayOf() }) val sslContext = SSLContext.getInstance("TLS") sslContext.init(null, trustAllCerts, java.security.SecureRandom()) val url = URL("https://epic7db.com") val sslParameters = SSLParameters() // 强制添加正确的SNI主机名 val sniHostNames = mutableListOf<SNIHostName>(SNIHostName(url.host)) sslParameters.serverNames = sniHostNames // 自定义SSLSocketFactory传递参数 val wrappedFactory = object : SSLSocketFactoryWrapper(sslContext.socketFactory, sslParameters) {} HttpsURLConnection.setDefaultSSLSocketFactory(wrappedFactory) HttpsURLConnection.setDefaultHostnameVerifier { _, _ -> true } val conn = url.openConnection() as HttpsURLConnection conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36") try { val content = String(conn.inputStream.readAllBytes()) println(content) } catch (e: Exception) { println("错误: ${e.message}") } finally { conn.disconnect() } } // 保留原SSLSocketFactoryWrapper辅助类 package http; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; public class SSLSocketFactoryWrapper extends SSLSocketFactory { private final SSLSocketFactory wrappedFactory; private final SSLParameters sslParameters; public SSLSocketFactoryWrapper(SSLSocketFactory factory, SSLParameters sslParameters) { this.wrappedFactory = factory; this.sslParameters = sslParameters; } @Override public Socket createSocket(String host, int port) throws IOException, UnknownHostException { SSLSocket socket = (SSLSocket) wrappedFactory.createSocket(host, port); setParameters(socket); return socket; } @Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { SSLSocket socket = (SSLSocket) wrappedFactory.createSocket(host, port, localHost, localPort); setParameters(socket); return socket; } @Override public Socket createSocket(InetAddress host, int port) throws IOException { SSLSocket socket = (SSLSocket) wrappedFactory.createSocket(host, port); setParameters(socket); return socket; } @Override public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { SSLSocket socket = (SSLSocket) wrappedFactory.createSocket(address, port, localAddress, localPort); setParameters(socket); return socket; } @Override public Socket createSocket() throws IOException { SSLSocket socket = (SSLSocket) wrappedFactory.createSocket(); setParameters(socket); return socket; } @Override public String[] getDefaultCipherSuites() { return wrappedFactory.getDefaultCipherSuites(); } @Override public String[] getSupportedCipherSuites() { return wrappedFactory.getSupportedCipherSuites(); } @Override public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { SSLSocket socket = (SSLSocket) wrappedFactory.createSocket(s, host, port, autoClose); setParameters(socket); return socket; } private void setParameters(SSLSocket socket) { socket.setSSLParameters(sslParameters); } }
方案2:禁用SNI扩展
若方案1无效,直接禁用SNI:在JVM启动参数添加-Djsse.enableSNIExtension=false,或在代码开头设置:
System.setProperty("jsse.enableSNIExtension", "false")
关键说明
- 网站特殊配置可能要求SNI字段必须严格匹配
epic7db.com,部分HTTP客户端自动处理逻辑不符合要求; - 生产环境请勿使用信任所有证书的代码,建议导入网站根证书做校验;
- 浏览器能正常访问是因为其SNI和Host头的处理逻辑更兼容这类特殊配置。
内容的提问来源于stack exchange,提问作者KM529
相关产品推荐
相关产品推荐

