【问题标题】:HTTP Ajax Request via HTTPS Page通过 HTTPS 页面的 HTTP Ajax 请求
【发布时间】:2021-03-15 06:21:33
【问题描述】:

我有一个网站,其中一些页面使用 HTTPS 连接。在这些 HTTPS 页面中,我必须使用 HTTP Ajax 请求来检索一些错误,例如空白字段。但是此错误消息不会出现。是否有任何解决方案,或者我必须发出 AJAX 请求才能在 HTTPS 连接上归档?

【问题讨论】:

  • ajax 应该在 https 上运行良好,你能发布你的实际代码 sn-p 吗?
  • 听起来像 SOP (en.wikipedia.org/wiki/Same_origin_policy):架构不同,因此来源不同。
  • 感谢您的回答。我已经相应地更改了我的网站。

标签: javascript ajax


【解决方案1】:

由于Same Origin Policy,这是不可能的。

您也需要将 Ajax 请求切换到 https。

【讨论】:

  • 即使是跨域资源共享的工作草案也无法实现:w3.org/TR/cors/#user-agent-security
  • 感谢大家的回答。我根据同源政策更改了我的网站。
  • @NickSotiros 为什么您不希望它安全?缺点为零,HTTPS 页面上的 HTTP 请求可能会被 MITM 攻击以注入恶意 JS。
  • @ceejayoz 好吧,如果你下载一个 js 脚本并执行它,你可能会受到 MITM 的攻击。但是如果你只是想在你的 CSS 中使用别人的背景图片或者下载一个 youtube 视频,你就不能。为什么浏览器假定通过 ajax 请求加载的内容将是 javascript 来执行?有一个网站prezi.com,它允许您使用从外部资源中提取的在线内容生成在线演示文稿,它们必须使用代理。
  • @NickSotiros 实际上,某人的 css 可以挂钩输入并将这些输入中输入的所有数据发送到错误的服务器。
【解决方案2】:

如果没有任何服务器端解决方案,安全页面只有一种方式可以从不安全的页面/请求中获取信息,这就是 postMessage 和弹出窗口

我说弹出窗口是因为该网站不允许混合内容。但是弹出窗口并没有真正混合。它有自己的窗口,但仍然可以通过 postMessage 与开启者通信。

因此,您可以使用 window.open(...) 打开一个新的 http 页面并让该页面为您发出请求


XDomain 是我写这篇文章的时候想到的,但这是一种使用新 fetch api 的现代方法,优点是大文件的流式传输,缺点是它不适用于所有浏览器

您将此代理脚本放在任何 http 页面上

onmessage = evt => {
  const port = evt.ports[0]

  fetch(...evt.data).then(res => {
    // the response is not clonable
    // so we make a new plain object
    const obj = {
      bodyUsed: false,
      headers: [...res.headers],
      ok: res.ok,
      redirected: res.redurected,
      status: res.status,
      statusText: res.statusText,
      type: res.type,
      url: res.url
    }

    port.postMessage(obj)

    // Pipe the request to the port (MessageChannel)
    const reader = res.body.getReader()
    const pump = () => reader.read()
    .then(({value, done}) => done 
      ? port.postMessage(done)
      : (port.postMessage(value), pump())
    )

    // start the pipe
    pump()
  })
}

然后您在 https 页面中打开一个弹出窗口(请注意,您只能在用户交互事件中执行此操作,否则它将被阻止)

window.popup = window.open(http://.../proxy.html)

创建你的实用函数

function xfetch(...args) {
  // tell the proxy to make the request
  const ms = new MessageChannel
  popup.postMessage(args, '*', [ms.port1])

  // Resolves when the headers comes
  return new Promise((rs, rj) => {

    // First message will resolve the Response Object
    ms.port2.onmessage = ({data}) => {
      const stream = new ReadableStream({
        start(controller) {

          // Change the onmessage to pipe the remaning request
          ms.port2.onmessage = evt => {
            if (evt.data === true) // Done?
              controller.close()
            else // enqueue the buffer to the stream
              controller.enqueue(evt.data)
          }
        }
      })

      // Construct a new response with the 
      // response headers and a stream
      rs(new Response(stream, data))
    }
  })
}

然后像平常一样使用 fetch api 发出请求

xfetch('http://httpbin.org/get')
  .then(res => res.text())
  .then(console.log)

【讨论】:

  • 很好,创建了一个模块cors-bypass,可以无缝地执行此操作。
  • 为什么要打开一个新窗口?您不能将请求放入 iframe 中吗?
  • @Chiwda 不,因为您将安全内容与不安全内容混合在一起,因此使用弹出窗口不会混合
  • 我终于用一种非常简单的方式做到了:w = window.open("",'_blank', 'toolbar=no,titlebar=no,status=no,menubar=no,scrollbars=否,可调整大小=否,左=12000,顶部=12000,宽度=10,高度=10,可见=无',''); w.location.href = MyURI; setTimeout(function() { w.close(); }, 6000)
【解决方案3】:

不过,这可以通过以下步骤完成:

  1. 向您的网站(同一域)发送 https ajax 请求

    jQuery.ajax({
        'url'      : '//same_domain.com/ajax_receiver.php',
        'type'     : 'get',
        'data'     : {'foo' : 'bar'},
        'success'  : function(response) {
            console.log('Successful request');
        }
    }).fail(function(xhr, err) {
        console.error('Request error');
    });
    
  2. 获取 ajax 请求,例如通过 php,并通过 http 向任何所需的网站发出 CURL 获取请求。

    use linslin\yii2\curl;
    $curl = new curl\Curl();
    $curl->get('http://example.com');
    

【讨论】:

  • 这个概念非常有效(使用与我的设置/项目相关的代码)。我在我的服务器上创建了一个 php 文件,并在 HTTP Url 上做了一个 curl 请求。我从我的 HTTPS 网站调用了这个文件,并发送了 API 所需的变量,瞧!
  • 我只知道可能的端点,如何在我的网站上使用这个方法。我的网站是 https,API 是 http://5ty.org:8080/api/card/post
  • 不利的一面是,如果您的页面有很多并发请求,那么您的服务器可能会饱和。
【解决方案4】:

在某些情况下,可以在没有 SSL 证书的情况下向 TCP 服务器发送没有响应的单向请求。与 HTTP 服务器相比,TCP 服务器会捕获您的请求。但是,将无法访问从浏览器发送的任何数据,因为浏览器不会在没有积极的证书检查的情况下发送任何数据。在特殊情况下,即使是没有任何数据的裸 TCP 信号也足以执行某些任务。例如,局域网内的物联网设备启动与外部服务的连接。 Link

这是一种“唤醒”触发器,可以在没有任何安全措施的端口上工作。

如果需要响应,可以使用安全的公共 https 服务器来实现,该服务器可以使用例如将所需数据发送回浏览器。网络套接字。

【讨论】:

    【解决方案5】:

    我创建了一个名为cors-bypass 的模块,它允许您在不需要服务器的情况下执行此操作。它使用postMessage发送跨域事件,用于提供模拟HTTP API(fetchWebSocketXMLHTTPRequest等)。

    它与answer by Endless 基本相同,但无需更改代码即可使用它。

    使用示例:

    import { Client, WebSocket } from 'cors-bypass'
    
    const client = new Client()
    
    await client.openServerInNewTab({
      serverUrl: 'http://random-domain.com/server.html',
      adapterUrl: 'https://your-site.com/adapter.html'
    })
    
    const ws = new WebSocket('ws://echo.websocket.org')
    ws.onopen = () => ws.send('hello')
    ws.onmessage = ({ data }) => console.log('received', data)
    

    【讨论】:

      【解决方案6】:

      在 server.js 中创建一个绕过 API。这对我有用。

      app.post('/by-pass-api',function(req, response){
        const url = req.body.url;
        console.log("calling url", url);
        request.get(
          url,
          (error, res, body) => {
            if (error) {
              console.error(error)
              return response.status(200).json({'content': "error"}) 
      }
              return response.status(200).json(JSON.parse(body))
              },
            )
          })
      

      并使用 axios 调用它或像这样获取:

      const options = {
           method: 'POST',
           headers: {'content-type': 'application/json'},
           url:`http://localhost:3000/by-pass-api`, // your environment 
           data: { url },  // your https request here
          };
      

      【讨论】:

        【解决方案7】:

        从 javascript 我尝试了几种方法,但我做不到。

        您需要一个服务器端解决方案,例如在 c# 上,我确实创建了一个控制器来调用 http,然后反序列化对象,结果是当我从 javascript 调用时,我正在从我的 @ 发出请求987654321@ 到我的 htpps:// 域。请看我的c#代码:

        [Authorize]
        public class CurrencyServicesController : Controller
        {
            HttpClient client;
            //GET: CurrencyServices/Consultar?url=valores?moedas=USD&alt=json
            public async Task<dynamic> Consultar(string url)
            {
                client = new HttpClient();
                client.BaseAddress = new Uri("http://api.promasters.net.br/cotacao/v1/");
                client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
                System.Net.Http.HttpResponseMessage response = client.GetAsync(url).Result;
        
                var FromURL = response.Content.ReadAsStringAsync().Result;
        
                return JsonConvert.DeserializeObject(FromURL);
            }
        

        让我向你展示我的客户端(Javascript)

        <script async>
        $(document).ready(function (data) {
        
            var TheUrl = '@Url.Action("Consultar", "CurrencyServices")?url=valores';
            $.getJSON(TheUrl)
                .done(function (data) {
                    $('#DolarQuotation').html(
                        '$ ' + data.valores.USD.valor.toFixed(2) + ','
                    );
                    $('#EuroQuotation').html(
                        '€ ' + data.valores.EUR.valor.toFixed(2) + ','
                    );
        
                    $('#ARGPesoQuotation').html(
                        'Ar$ ' + data.valores.ARS.valor.toFixed(2) + ''
                    );
        
                });       
        
        });
        

        希望对您有所帮助! 问候

        【讨论】:

          猜你喜欢
          • 2010-11-04
          • 2012-05-01
          • 2013-01-20
          • 2011-01-07
          • 2012-10-12
          • 2013-02-28
          • 1970-01-01
          • 2011-11-17
          相关资源
          最近更新 更多