简体   繁体   中英

HTTP Ajax Request via HTTPS Page

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?

This is not possible due to the Same Origin Policy .

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

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

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.

So you can open a new http-page with window.open(...) and have that making the request for you


XDomain came 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

You put this proxy script on any http page

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)

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

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

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');

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

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 eg Websockets.

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

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

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)

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

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:

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

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

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://domain to my htpps://domain. Please see my c# code:

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

<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

This works for me. Make a bypass API in server.js or index.js. I am using express.js library.

import express from 'express';
import bodyParser from 'body-parser'; // custom_code
import axios from 'axios'; // custom-code
let app = express();
const jsonParser = bodyParser.json();

app.post('/by-pass-api', jsonParser, async (req, response) => {
  const { url } = req.body;
  const data = { data: req.body.data };
  const result = await axios.post(url, data);
  response.send({ success: true, result: result });
});
  


app.listen(3000, () => {
    console.log(`Server is running as on port 3000`);
  });

Create a function to call your localhost server(your application server) using axios or fetch like this:

url: http://your-http-api-url : This is external http url.

axios.post("http://localhost:3000/by-pass-api", {
              headers: { "content-type": "application/json" },
              url: `http://your-http-api-url`,
              data: {...your_payload},
            })

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM