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?

Answers:

Answer

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 (that is if the site is using CORS as well)


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

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

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 e.g. Websockets.

Answer

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

Answer

This is not possible due to the Same Origin Policy.

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

Answer

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

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

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.