【问题标题】:https request via https proxy but return 'unknown protocol:openssl ' error通过 https 代理的 https 请求,但返回“未知协议:openssl”错误
【发布时间】:2018-12-28 14:27:05
【问题描述】:

如果我通过“HTTP”代理请求“HTTP”地址,一切都很好

    const rq = require('request-promise'); 
    try {
    let res = rq({
        url: 'http://xxxx',
        timeout: TIME_OUT,
        gzip: true,
        proxy: 'http://112.25.60.32:8080'
    });
    res.then(res => {
        console.log('res');
        console.log(res);
    }).catch(err => {
        console.log(err);
    });
} catch (error) {
    console.log(error);
}

但是如果通过“https”代理请求“https”地址,它将返回“未知协议”

RequestError:错误:无法建立隧道套接字,原因=写入 EPROTO 101057795:错误:140770FC:SSL 例程:SSL23_GET_SERVER_HELLO:未知协议:openssl\ssl\s23_clnt.c:827:

try {
    let res = rq({
        url: 'https://ipinfo.io/', //  https address
        timeout: TIME_OUT,
        gzip: true,
        rejectUnauthorized: false,
        proxy: 'https://149.56.109.24:3128' //  https proxy
    });
    res.then(res => {
        console.log('res');
        console.log(res);
    }).catch(err => {
        console.log(err);
    });
} catch (error) {
    console.log(error);
}

一开始我以为是代理地址的问题。但是相同的代理地址在 python 请求模块中工作正常

python 代码

import requests, os
os.environ['HTTP_PROXY'] = '112.25.60.32:8080'
os.environ['HTTPS_PROXY'] = '149.56.109.24:3128'
try:
    text = requests.get('https://ipinfo.io/').text # request https address
except Exception as e:
    print(e)
    print('connect failed')
print(text) 
# it works fine!  {
  "ip": "149.56.109.24:3128", 
  "hostname": "181.ip-158-69-206.net",
  "city": "Montreal",
  "region": "Quebec",
  "country": "CA",
  "loc": "45.5000,-73.5833",
  "postal": "H3A",
  "org": "AS16276 OVH SAS"
}
# The returned 'ip' information is the 'https' proxy address.

在 StackOverflow 中发现了类似的问题。有人回复说是端口问题。

这里是链接StackOverflow

但我认为这不是端口的问题,因为当我使用 fiddler 代理时,它可以工作!

这是我关于提琴手的配置

代码(由提琴手提供)

try {
  let res = rq({
    url: 'https://ipinfo.io/',
    timeout: TIME_OUT,
    gzip: true,
    rejectUnauthorized: false,
    proxy: 'http://127.0.0.1:8888' // through fiddler
  });
  res
    .then(res => {
      console.log('res');
      console.log(res); // it works!!
    })
    .catch(err => {
      console.log(err);
    });
} catch (error) {
  console.log(error); 
}

但是,根据上面的代码,Proxy改为'149.56.109.24:3128'(没有fiddler)还是会报'unknown protocol:openssl\ssl\s23_clnt.c:827'错误

所以出了什么问题?我还没解决。

【问题讨论】:

    标签: node.js ssl https proxy request


    【解决方案1】:
       proxy: 'https://149.56.109.24:3128' //  https proxy
    

    HTTP 代理将处理 HTTP 和 HTTPS。 HTTPS 的处理方式是直接连接到 HTTP 代理,发出 CONNECT 请求以建立到服务器的隧道,然后在该隧道内升级到 TLS 的连接 - 这会产生端到端 HTTPS。

    您改为配置的是通过 HTTPS 访问代理本身,本质上是在 HTTPS 隧道内请求 HTTPS。代理很可能不支持,即使用http:// 访问代理而不是https://。

    【讨论】:

    • 你知道一些支持这个的官方文档吗?我不怀疑,我只是想证明一个技术决定的合理性。
    • 我不确定您期望什么样的文档。但是你可以看看这需要如何配置,例如使用 curl 或在浏览器中,你会看到相同的。如果您清楚底层 CONNECT 方法(记录在 here)的工作原理以及它允许​​您为 TLS 端到端连接创建隧道,这可能会有所帮助。
    • 谢谢。作为记录,我只是想用提琴手正确地制作节点代理。我很确定我过去曾使用 https 代理处理 https 请求,但最近它不起作用并挂起请求,与 SSL23_GET_SERVER_HELLO:unknown protocol 超时但 http 有效,所以我证明这是正确的方法和不是结果/开发环境特定的。在我的代码中引用这个答案作为理由。
    • 刚刚看到此评论,对于任何阅读此评论的人来说——嵌套 TLS 完全没问题,并且在代理是 HTTPS 服务器的任何地方都可以完成。作为参考,请查看 GO 对此案例的实现:golang.org/src/net/http/transport.goAdd TLS to a persistent connection, i.e. negotiate a TLS session. If pconn is already a TLS tunnel, this function establishes a nested TLS session inside the encrypted channel.
    • @omricoco:代理只是HTTP,但仍然可以通过CONNECT方法端到端访问https://。一个典型的错误是假设需要使用 HTTPS 访问代理才能访问https:// 站点。此常见错误与 一些 客户端和代理支持通过 HTTPS 访问代理的技术能力无关,这可以保护通往代理的http:// 和https:// 流量。请注意,这不是普遍支持的(尽管正在增长),例如Python 不支持这个。
    猜你喜欢
    • 1970-01-01
    • 2012-07-31
    • 2018-05-17
    • 2013-11-01
    • 2015-04-07
    • 1970-01-01
    • 2019-01-09
    • 2018-07-16
    • 2015-10-16
    相关资源
    最近更新 更多