Javascript 通过 HTTPS 页面的 HTTP Ajax 请求

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4032104/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 07:12:20  来源:igfitidea点击:

HTTP Ajax Request via HTTPS Page

javascriptajax

提问by cooldude

I am having a site with some pages on HTTPS connection. From these HTTPS pages, I have to use a HTTP Ajax request for some errors retrieval like blank fields. But this error messages are not coming. Is there any solution to it or I have to make that AJAX request to file on HTTPS connection?

我有一个包含 HTTPS 连接页面的站点。在这些 HTTPS 页面中,我必须使用 HTTP Ajax 请求来检索一些错误,例如空白字段。但是此错误消息不会出现。是否有任何解决方案,或者我必须将该 AJAX 请求提交到 HTTPS 连接上?

回答by Pekka

This is not possible due to the Same Origin Policy.

由于同源策略,这是不可能的。

You will need to switch the Ajax requests to https, too.

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

回答by Endless

Without any server side solution, Theres is only one way in which a secure page can get something from a insecure page/request and that's thought postMessage and a popup

没有任何服务器端解决方案,只有一种方法可以让安全页面从不安全的页面/请求中获取某些内容,这就是 postMessage 和弹出窗口

I said popup cuz the site isn't allowed to mix content. But a popup isn't really mixing. It has it's own window but are still able to communicate with the opener with postMessage.

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

So you can open a new http-page with window.open(...)and have that making the request for you (that is if the site is using CORS as well)

因此,您可以打开一个新的 http 页面,window.open(...)并让该页面为您发出请求(也就是说,如果该站点也使用 CORS)



XDomaincame to mind when i wrote this but here is a modern approach using the new fetch api, the advantage is the streaming of large files, the downside is that it won't work in all browser

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

You put this proxy script on any http page

您将此代理脚本放在任何 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()
  })
}

Then you open a popup window in your https page (note that you can only do this on a user interaction event or else it will be blocked)

然后你在你的 https 页面中打开一个弹出窗口(注意你只能在用户交互事件上这样做,否则它会被阻止)

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

create your utility function

创建您的效用函数

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))
    }
  })
}

And make the request like you normally do with the fetch api

并像通常使用 fetch api 一样发出请求

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

回答by Maxim Ilin

Still, this can be done with the following steps:

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

  1. send an https ajax request to your web-site (the same domain)

    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. get ajax request, for example, by php, and make a CURL get request to any desired website via http.

    use linslin\yii2\curl;
    $curl = new curl\Curl();
    $curl->get('http://example.com');
    
  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. 例如,通过 php 获取 ajax 请求,并通过 http 向任何所需的网站发出 CURL 获取请求。

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

回答by user2080851

In some cases a one-way request without a response can be fired to a TCP server, without a SSL certificate. A TCP server, in contrast to a HTTP server, will catch you request. However there will be no access to any data sent from the browser, because the browser will not send any data without a positive certificate check. And in special cases even a bare TCP signal without any data is enough to execute some tasks. For example for an IoT device within a LAN to start a connection to an external service. Link

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

This is a kind of a "Wake Up" trigger, that works on a port without any security.

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

In case a response is needed, this can be implemented using a secured public https server, which can send the needed data back to the browser using e.g. Websockets.

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

回答by Enrique Mingyar Torrez Hinojos

From the javascript I tried from several ways and I could not.

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

You need an server side solution, for example on c# I did create an controller that call to the http, en deserialize the object, and the result is that when I call from javascript, I'm doing an request from my https://domainto my htpps://domain. Please see my c# code:

您需要一个服务器端解决方案,例如在 c# 上,我确实创建了一个调用 http、反序列化对象的控制器,结果是当我从 javascript 调用时,我正在从https://发出请求到我的 htpps://domain。请看我的 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);
    }

And let me show to you my client side (Javascript)

让我向你展示我的客户端(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) + ''
            );

        });       

});

I wish that this help you! Greetings

我希望这对你有帮助!你好

回答by samdd

I've created a module called cors-bypass, that allows you to do this without the need for a server. It uses postMessageto send cross-domain events, which is used to provide mock HTTP APIs (fetch, WebSocket, XMLHTTPRequestetc.).

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

It fundamentally does the same as the answer by Endless, but requires no code changes to use it.

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

Example usage:

用法示例:

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)

回答by Nikita Khanna

Make a bypass API in server.js. This works for me.

在 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))
        },
      )
    })

And call it using axios or fetch like this:

并使用 axios 或 fetch 调用它,如下所示:

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