„Zawartość mieszana zablokowana” podczas wykonywania operacji HTTP AJAX na stronie HTTPS

111

Mam formularz, który przesyłam (przez GET, ponieważ jest to wymagane) do CRM (ViciDial). Mogę pomyślnie przesłać formularz, ale jeśli to zrobię, plik przetwarzania w CRM po prostu wyświetli tekst o powodzeniu i to wszystko.

Zamiast tego tekstu chcę wyświetlić stronę z podziękowaniami w mojej witrynie, więc zdecydowałem się użyć AJAX do przesłania formularza i przekierowania go na potrzebną stronę, jednak w mojej przeglądarce pojawia się ten błąd:

Zawartość mieszana: strona pod adresemhttps://page.com ” została załadowana przez HTTPS, ale zażądała niezabezpieczonego punktu końcowego XMLHttpRequest „ http://XX.XXX.XX.XXX/vicidial/non_agent_api.php?queries=query=data ”. To żądanie zostało zablokowane; zawartość musi być dostarczana przez HTTPS.

To jest mój skrypt AJAX:

    <script>
    SubmitFormClickToCall = function(){

        jQuery.ajax({
            url: "http://XX.XXX.XX.XX/vicidial/non_agent_api.php",
            data : jQuery("#form-click-to-call").serialize(),
            type : "GET",
            processData: false,
            contentType: false,
            success: function(data){
                window.location.href = "https://www.example.com/thank-you";
            }
        });
    }
    </script>

Samo ustawienie https w adresie URL nie zadziała. Czy jest jakiś sposób, w jaki mogę przesłać dane za pomocą GET i przekierować użytkownika na moją stronę z podziękowaniami?

============================

Problem dotyczył mieszanej zawartości, co oznacza, że ​​załadowałem stronę przez HTTPS i próbowałem trafić przez AJAX do API, które było w HTTP. Ale przeglądarka nie pozwoli nam tego po prostu zrobić.

Więc jeśli nie możesz ustawić API na HTTPS (to był mój przypadek), nadal możemy podejść do tego w inny sposób.

Głównym problemem nie był problem z mieszaną zawartością, chodziło o to, że chciałem przesłać dane do API i przekierować użytkowników na fantazyjną stronę z podziękowaniami. Zamiast używać AJAX, utworzyłem plik php, który odbiera dane, wysyła je za pomocą curl do API (ponieważ jest to robione po stronie serwera, nie ma problemu z mieszaną zawartością) i przekierowuje mojego zadowolonego użytkownika na fantazyjną stronę z podziękowaniami.

StormRage
źródło
Czy masz bezpieczną wersję swojego interfejsu API? Jeśli używasz bezpiecznej witryny jako źródła, musisz wysyłać żądania przez HTTPS.
Cameron Tinker
1
Nie, nie wiem, czy jest inny sposób, w jaki mógłbym to zrobić? Chodzi mi o to, że prośba zostanie przesłana, jeśli po prostu skorzystaj z formularza przesyłania bez Ajax
StormRage
Możesz utworzyć adres URL HTTPS w Apache do proxy XX.XXX.XX.XXprzez HTTP. Jeśli jednak celem protokołu HTTP jest ochrona informacji użytkownika, należy uważać, aby trasa między serwerami nie przebiegała przez publiczny Internet.
halfer

Odpowiedzi:

93

Jeśli załadujesz stronę w przeglądarce przy użyciu HTTPS, przeglądarka odmówi załadowania jakichkolwiek zasobów przez HTTP. Jak już próbowałeś, zmiana adresu URL interfejsu API na HTTPS zamiast HTTP zazwyczaj rozwiązuje ten problem . Jednak Twój interfejs API nie może zezwalać na połączenia HTTPS. Z tego powodu musisz albo wymusić HTTP na stronie głównej, albo zażądać, aby zezwalały na połączenia HTTPS.

Uwaga: żądanie będzie nadal działać, jeśli przejdziesz do adresu URL interfejsu API zamiast próbować go załadować za pomocą AJAX. Dzieje się tak, ponieważ przeglądarka nie ładuje zasobu z zabezpieczonej strony, zamiast tego ładuje niezabezpieczoną stronę i akceptuje to. Jednak aby był dostępny przez AJAX, protokoły powinny być zgodne.

Mikel Bitson
źródło
1
OK, interfejs API jest na moim serwerze, czy jest jakiś przewodnik, który mogę zastosować, aby ustawić go na https?
StormRage
1
@StormRage Absolutnie! Jaki typ serwera używasz? Apache? Czy jest to hosting współdzielony czy prywatny serwer?
Mikel Bitson
@StormRage Daj mi znać, jeśli potrzebujesz dalszej pomocy. W przeciwnym razie głosowanie zachęci do pomocy publicznej, którą otrzymujesz na SO.
Mikel Bitson
1
Przepraszam, że się spóźniłem, udało mi się go rozwiązać bez użycia AJAX, moje rozwiązania zawierają niektóre funkcje wordpress / curl php, opublikuję moje rozwiązanie tak szybko, jak to możliwe, czy powinienem po prostu edytować moje pytanie i napisać w nim swoje rozwiązanie, lub czy powinienem użyć przycisku z napisem „odpowiedz na własne pytanie”?
StormRage,
1
Podkreślono tutaj odpowiednią część odpowiedzi. Jedynym praktycznym rozwiązaniem jest użycie HTTPS
Liam
132

Rozwiązałem to, dodając następujący kod do strony HTML, ponieważ używamy interfejsu API strony trzeciej, który nie jest przez nas kontrolowany.

<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> 

Mam nadzieję, że to pomoże i to również dla rekordu.

Niebo
źródło
8
Spowoduje to uaktualnienie wszystkich httpżądań do użycia https, więc nie musisz zmieniać protokołu dla każdego połączenia.
wysłano
3
To zadziałało dla mnie, ale niestety nie działa z Internet Explorerem: developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ ...
Ciaran Gallagher
2
Próbowałem tego, ale teraz otrzymuję błąd CORS w przeglądarce Firefox i net :: ERR_SSL_PROTOCOL_ERROR w przeglądarce Chrome. Wiem, że wszystkie połączenia działają, ponieważ moja strona internetowa miała wcześniej protokół http, ale teraz, gdy zmieniłem na https, te połączenia nie działają. czy jest jeszcze coś, co mogę dodać do mojego głównego pliku HTML? Ponieważ jeśli podążę za krokami @Juanma Menendez, wszystkie połączenia działają, ale nie mogę oczekiwać, że każdy użytkownik to zrobi.
Otorrinolaringologista -man
Zmagałem się z tym problemem przez wiele godzin, aż znalazłem twoją odpowiedź, wielkie dzięki!
Muhab
Potwierdzamy, że to rozwiązanie działa w naszym przypadku, ale może też ci pomoże w przyszłości: próbowaliśmy wprowadzić posegmentowaną funkcję przesyłania strumieniowego na żywo HTTP / wideo na żądanie, coś w rodzaju www.example.com/blabla/master.m3u8. Wszystko działało dobrze na http. Ale kiedy przeprowadzamy migrację do https, po prostu nie zadziała. Dowiedzieliśmy się, że inicjator master.m3u8był w stanie wykonać httpsżądanie, ale następujący fragment wideo był zawsze używany http(ponieważ używamy modułu innej firmy). Bez względu na to, co ulepszymy, po prostu nie będzie używane https. Skorzystałem z tej polityki i od razu zadziałało jak urok!
rahmatns
34

Jeśli właśnie odwiedzasz zaufaną stronę internetową i chcesz szybko przejść do przodu, po prostu:

1- Kliknij ikonę tarczy po prawej stronie paska adresu.

Zezwalaj na zawartość mieszaną w Google Chrome

2- W wyskakującym okienku kliknij „Mimo to wczytaj” lub „Załaduj niebezpieczny skrypt” (w zależności od wersji Chrome).


Jeśli chcesz ustawić przeglądarkę Chrome na ZAWSZE (na wszystkich stronach internetowych) zezwalającą na zawartość mieszaną:

1- W otwartej przeglądarce Chrome naciśnij Ctrl + Shift + Q na klawiaturze, aby wymusić zamknięcie Chrome. Chrome musi być całkowicie zamknięty przed następnymi krokami.

2- Kliknij prawym przyciskiem myszy ikonę Google Chrome na pulpicie (lub łącze w menu Start). Wybierz Właściwości.

3- Na końcu istniejących informacji w polu Cel dodaj: „--allow-running-insecure-content” (jest spacja przed pierwszym myślnikiem).

4- Kliknij OK.

5- Otwórz Chrome i spróbuj uruchomić zawartość, która została wcześniej zablokowana. Teraz powinno działać.

Juanma Menendez
źródło
4
Nie robi to nic dla osób projektujących strony internetowe dla tych użytkowników, którzy nie chcą zmieniać swoich ustawień, aby witryna działała w ich przeglądarce, na przykład OP.
smallpants
13

Przyczyna tego błędu jest bardzo prosta. Twój AJAX próbuje nawiązać połączenie przez HTTP, podczas gdy twój serwer działa przez HTTPS, więc twój serwer odmawia wywołania AJAX. Można to naprawić, dodając następujący wiersz w tagu head głównego pliku HTML:

<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> 
Sobhan Niroula
źródło
pozwala na to, ale żądanie to https
BG BRUNO
W moim przypadku. tylko żądanie HTTP serwera. Próbuję tego <meta> nie działa. Przeglądarka zgłasza błąd żądania pod adresem URL.
iHad 169
1

Jeśli twój kod API działa na serwerze node.js , musisz skupić swoją uwagę na tym, a nie w Apache czy NGINX. Mikel ma rację, zmiana adresu URL API na HTTPS jest odpowiedzią, ale jeśli twoje API wywołuje serwer node.js, lepiej ustawić go na HTTPS! I oczywiście serwer node.js może znajdować się na dowolnym nieużywanym porcie, nie musi to być port 443.

mcmacerson
źródło
Interfejs API był stroną trzecią, więc nie było możliwości ustawienia go na https, a jak widać w
adresie
@StormRage Twoje pytanie i odpowiedź Mikela doprowadziły do ​​rozwiązania mojego problemu, więc pomyślałem, że zanotuję to tutaj, mimo że moja odpowiedź tak naprawdę nie odnosi się do Twojej sytuacji.
mcmacerson,
Cóż, ty i Mikel macie rację, najbardziej rozsądnym rozwiązaniem byłoby użycie ssl w API, ale w tym kontekście nie byłem w stanie tego zrobić, ponieważ było to API innej firmy, ale rozwiązanie dla ppl za pomocą wordpress lub każda starsza witryna może wysyłać dane do swojego zaplecza i wysyłać żądanie do interfejsu API na serwerze.
StormRage,
Zaimplementowałem interfejs API firmy laravel jako aplikację po stronie serwera i aplikację jonową jako PWA na tym samym hoście, więc mam ten sam błąd wymieniony w tym artykule stackoverflow.com/q/56157129/308578
saber tabatabaee yazdi
1

Zamiast używać metody Ajax Post, możesz użyć dynamicznego formularza wraz z elementem. Będzie działać, nawet jeśli strona jest załadowana w SSL, a przesłane źródło nie jest SSL.

Musisz ustawić wartość wartości elementu formularza.

W rzeczywistości nowy dynamiczny formularz zostanie otwarty jako tryb bez SSL w osobnej karcie przeglądarki, gdy atrybut docelowy ustawił „_blank”

var f = document.createElement('form');
f.action='http://XX.XXX.XX.XX/vicidial/non_agent_api.php';
f.method='POST';
//f.target='_blank';
//f.enctype="multipart/form-data"

var k=document.createElement('input');
k.type='hidden';k.name='CustomerID';
k.value='7299';
f.appendChild(k);



//var z=document.getElementById("FileNameId")
//z.setAttribute("name", "IDProof");
//z.setAttribute("id", "IDProof");
//f.appendChild(z);

document.body.appendChild(f);
f.submit()
Proneet Ray
źródło
Właściwie chcę trafić do API, ale kiedy robię to z twoją metodą, wykonując żądanie get, faktycznie wysyłałbym formularz, ale teraz utknąłem z odczytaniem odpowiedzi z API. Bo myślę, że dla tego AJAX lub xmlhttprequest jest jedyną opcją
Siddharth Choudhary
ciekawe rozwiązanie :-)
BG BRUNO
proste i genialne
Harkal
0

Miałem ten sam problem, ale dla mnie problemem była komenda ng build. Robiłem "ng build --prod" i poprawiłem to na "ng build --prod --base-href / applicationname /". i to rozwiązało mój problem.

Narender Gandi
źródło
0

w moim przypadku moim lokalnym hostem był, httpa moja wdrożona wersja to https, więc użyłem tego skryptu, aby dodać metatag http-equiv tylko dla https:

if (window.location.protocol.indexOf('https') == 0){
  var el = document.createElement('meta')
  el.setAttribute('http-equiv', 'Content-Security-Policy')
  el.setAttribute('content', 'upgrade-insecure-requests')
  document.head.append(el)
}
yaya
źródło