Güvensiz yanıt veya bağlantının reddedilmesi nedeniyle ajax çağrısının başarısız olup olmadığını belirleyin


115

Çok fazla araştırma yaptım ve bunun üstesinden gelmenin bir yolunu bulamadım. Özel bir kendinden imzalı sertifika ile jetty çalıştıran bir locahost https sunucusuna https sunucusundan jQuery ajax çağrısı yapmaya çalışıyorum. Benim sorunum, yanıtın reddedilen bir bağlantı mı yoksa güvenli olmayan bir yanıt mı olduğunu belirleyemem (sertifika kabulünün olmaması nedeniyle). Her iki senaryo arasındaki farkı belirlemenin bir yolu var mı? responseTextVe statusCodekrom konsolunda bir fark görebiliyor ama her zaman her iki durumda da aynıdır:

net::ERR_INSECURE_RESPONSE
net::ERR_CONNECTION_REFUSED

responseTexther zaman "" ve statusCodeher iki durumda da "0" dır.

Sorum şu, bir jQuery ajax çağrısının neden ERR_INSECURE_RESPONSEveya nedeniyle başarısız olup olmadığını nasıl belirleyebilirim ERR_CONNECTION_REFUSED?

Sertifika kabul edildikten sonra her şey yolunda gidiyor, ancak localhost sunucusunun kapatılıp kapatılmadığını veya çalışıp çalışmadığını bilmek istiyorum ancak sertifika henüz kabul edilmedi.

$.ajax({
    type: 'GET',
    url: "https://localhost/custom/server/",
    dataType: "json",
    async: true,
    success: function (response) {
        //do something
    },
    error: function (xhr, textStatus, errorThrown) {
        console.log(xhr, textStatus, errorThrown); //always the same for refused and insecure responses.
    }
});

görüntü açıklamasını buraya girin

İsteği manuel olarak gerçekleştirirken bile aynı sonucu alıyorum:

var request = new XMLHttpRequest();
request.open('GET', "https://localhost/custom/server/", true);
request.onload = function () {
    console.log(request.responseText);
};
request.onerror = function () {
    console.log(request.responseText);
};
request.send();

6
kodumu göndereceğim, ancak bu bir javascript kodu hatası değil. Lütfen sorumu dikkatlice okuyunuz.
taxicala

1
Diğer iki hata geri arama bağımsız değişkeni herhangi bir ek fikir veriyor mu? function (xhr, status, msg) {...Olacaklarından şüpheliyim ama denemeye değer.
Kevin B

2
Hayır. Bir sunucudan başka bir sunucuya. İskele sunucusu (locahost'ta çalışan) CORS başlıklarını düzgün bir şekilde ayarladı çünkü sertifikayı kabul ettiğimde her şey beklendiği gibi çalışıyor. Sertifikanın kabul edilmesi gerekip gerekmediğini veya iskelenin kapalı olup olmadığını belirlemek istiyorum.
taxicala

5
Tarayıcıdan bilgi eksikliğinin tamamen kasıtlı olması tamamen mümkündür. Basitçe bir "hata" önerilen bir bilgisayar korsanına bir miktar bilgi sağlar, örn. "Bu sistemde bağlantı noktası vb. Üzerinde dinleme yapan bir şey var ."
Katana314

1
bu istediğim bir şey değil, geliştirmekte olduğum şeyin tasarımı ve doğası gereği ihtiyacım olan bir şey. sunucu tarafı bir seçenek değil.
taxicala

Yanıtlar:


67

En yeni Web Tarayıcılarından ayırmanın bir yolu yoktur.

W3C Özellikleri:

Aşağıdaki adımlar, kullanıcı aracılarının basit bir çapraz kaynak talebi için ne yapması gerektiğini açıklar :

Talepte bulunma adımlarını uygulayın ve istekte bulunurken aşağıdaki istek kurallarına uyun.

Manuel yeniden yönlendirme bayrağı ayarlanmamışsa ve yanıt 301, 302, 303, 307 veya 308 HTTP durum koduna sahipse , yeniden yönlendirme adımlarını uygulayın.

Son kullanıcı isteği iptal ederse, iptal adımlarını uygulayın.

Ağ hatası varsa DNS hataları, TLS anlaşması hatası veya diğer tür ağ hataları durumunda, ağ hatası adımlarını uygulayın . Herhangi bir son kullanıcı etkileşimi talep etmeyin.

Not: Bu, 410 HTTP durum kodu gibi bazı hata türlerini gösteren HTTP yanıtlarını içermez.

Aksi takdirde, bir kaynak paylaşım kontrolü yapın. Başarısız olursa, ağ hatası adımlarını uygulayın. Aksi takdirde, pass dönerse, bu algoritmayı sonlandırın ve çapraz orijinli istek durumunu başarılı olarak ayarlayın. Aslında isteği sonlandırmayın.

Okuyabileceğiniz gibi, ağ hataları, hataları içeren HTTP yanıtını içermez, bu nedenle durum kodu olarak her zaman 0 ve hata olarak "" alacaksınız.

Kaynak


Not : Aşağıdaki örnekler, Google Chrome Sürüm 43.0.2357.130 kullanılarak ve OP birini taklit etmek için oluşturduğum bir ortama karşı yapılmıştır. Kurma kodu cevabın alt kısmındadır.


Bunu çözmek için bir yaklaşımın HTTPS yerine HTTP üzerinden ikincil bir istek yapmak olacağını düşündüm. Bu yanıt, ancak tarayıcıların daha yeni sürümlerinin karışık içeriği engellediği için bunun mümkün olmadığını hatırladım.

Bu, HTTPS kullanıyorsanız Web Tarayıcısının HTTP üzerinden bir isteğe izin vermeyeceği anlamına gelir ve bunun tersi de geçerlidir.

Bu, birkaç yıldan beri böyleydi, ancak Mozilla Firefox gibi eski Web Tarayıcısı sürümleri, 23 sürümleri buna izin veriyor.

Bununla ilgili kanıt:

HTTPS usign Web Broser konsolundan HTTP isteğinde bulunma

var request = new XMLHttpRequest();
request.open('GET', "http://localhost:8001", true);
request.onload = function () {
    console.log(request.responseText);
};
request.onerror = function () {
    console.log(request.responseText);
};
request.send();

aşağıdaki hataya neden olur:

Karışık İçerik: ' https: // localhost: 8000 / ' adresindeki sayfa HTTPS üzerinden yüklendi, ancak güvenli olmayan bir XMLHttpRequest uç noktası ' http: // localhost: 8001 / ' istedi . Bu istek engellendi; içerik HTTPS üzerinden sunulmalıdır.

Bunu bir Iframe eklemek gibi başka şekillerde yapmaya çalışırsanız, tarayıcı konsolunda aynı hata görünecektir.

<iframe src="http://localhost:8001"></iframe>

Soket bağlantısının kullanılması da bir cevap olarak gönderildi , sonucun aynı / benzer olacağından oldukça emindim ama denedim.

Güvenli olmayan bir soket uç noktasına HTTPS kullanarak Web Tarayıcısından bir soket bağlantısı açmaya çalışmak karma içerik hatalarıyla sonuçlanacaktır.

new WebSocket("ws://localhost:8001", "protocolOne");

1) Karışık İçerik: ' https: // localhost: 8000 / ' adresindeki sayfa HTTPS üzerinden yüklendi, ancak güvenli olmayan WebSocket uç noktası 'ws: // localhost: 8001 /' ile bağlanmaya çalıştı. Bu istek engellendi; bu uç nokta WSS üzerinden kullanılabilir olmalıdır.

2) Yakalanmamış DOMException: 'WebSocket' oluşturulamadı: Güvenli olmayan bir WebSocket bağlantısı HTTPS üzerinden yüklenmiş bir sayfadan başlatılamayabilir.

Sonra da bir wss uç noktasına bağlanmayı denedim.Ağ bağlantı hataları hakkında bazı bilgileri okuyabilir miyim?

var exampleSocket = new WebSocket("wss://localhost:8001", "protocolOne");
exampleSocket.onerror = function(e) {
    console.log(e);
}

Snippet'i Sunucu kapalıyken yürütmek şu sonuçları doğurur:

'Wss: // localhost: 8001 /' için WebSocket bağlantısı başarısız oldu: Bağlantı kurulurken hata: net :: ERR_CONNECTION_REFUSED

Yukarıdaki parçacığı Sunucu Açıkken yürütme

'Wss: // localhost: 8001 /' ile WebSocket bağlantısı başarısız oldu: WebSocket açılış anlaşması iptal edildi

Ancak yine, konsola gönderilen "hata işlevi" hatası, bir hatayı diğerinden ayırt etmek için herhangi bir ipucu vermez.


Bu yanıtın önerdiği gibi bir proxy kullanmak işe yarayabilir, ancak yalnızca "hedef" sunucunun genel erişimi varsa.

Burada durum böyle değildi, bu yüzden bu senaryoda bir proxy uygulamaya çalışmak Bizi aynı soruna götürecektir.

Node.js HTTPS sunucusu oluşturma kodu :

Kendinden imzalı sertifikalar kullanan iki Nodejs HTTPS sunucusu oluşturdum:

targetServer.js:

var https = require('https');
var fs = require('fs');

var options = {
    key: fs.readFileSync('./certs2/key.pem'),
    cert: fs.readFileSync('./certs2/key-cert.pem')
};

https.createServer(options, function (req, res) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
    res.writeHead(200);
    res.end("hello world\n");
}).listen(8001);

applicationServer.js:

var https = require('https');
var fs = require('fs');

var options = {
    key: fs.readFileSync('./certs/key.pem'),
    cert: fs.readFileSync('./certs/key-cert.pem')
};

https.createServer(options, function (req, res) {
    res.writeHead(200);
    res.end("hello world\n");
}).listen(8000);

Çalışmasını sağlamak için Nodejs'nin Yüklü olması gerekir, Her sunucu için ayrı sertifikalar oluşturmanız ve uygun şekilde certs ve certs2 klasörlerinde saklamanız gerekir.

Run To sadece yürütmek node applicationServer.jsve node targetServer.jsbir terminal (ubuntu örneğin) içinde.


6
Bu şimdiye kadarki en eksiksiz cevap. Aslında bazı araştırma çalışmaları ve testler yaptığınızı gösteriyor. Görüyorum ki, bunu gerçekleştirmek için mümkün olan her yolu denediniz ve tüm senaryolar gerçekten iyi açıklanmış. Hızlı bir şekilde bir test ortamı oluşturmak için örnek kod da sağladınız! Gerçekten iyi iş çıkardın! Görüş için teşekkürler!
taxicala

Mükemmel cevap! Bununla birlikte, kendi kendine imzalanan sertifikaların, ayrı sunuculardan olmaları durumunda bir tarayıcıdan yine de hatalar oluşturacağını belirtmek isterim. @ecarrizo
FabricioG

Bir ağ hatasından bahsediyorsak, Muhtemelen konsolda hataları manuel olarak görebilirsiniz. ancak güvenli bir ortamda koddan ona erişemezsiniz.
ecarrizo

32

Şu an itibariyle: Bu olayı tarayıcılar arasında ayırt etmenin bir yolu yok. Tarayıcılar, geliştiricilerin erişmesi için bir etkinlik sağlamaz. (Temmuz 2015)

Bu cevap yalnızca potansiyel, albiet hacky ve eksik bir çözüm için fikirler sağlamayı amaçlamaktadır.


Sorumluluk reddi: Bu yanıt, OP'nin sorunlarını tamamen çözmediğinden eksiktir (çapraz kaynak politikaları nedeniyle). Bununla birlikte, fikrin kendisi, bir proxy ve ajax kullanarak burada @artur grzesiak tarafından daha da genişletilen bazı haklara sahiptir .


Kendim de epeyce araştırma yaptıktan sonra, reddedilen bağlantı ile güvensiz bir yanıt arasındaki farkı kontrol etmenin herhangi bir biçimi yok gibi görünüyor, en azından javascript ikisi arasındaki farka bir yanıt verdiği sürece.

Araştırmamın genel fikir birliği, SSL sertifikalarının tarayıcı tarafından işlendiği yönündedir, bu nedenle kullanıcı tarafından kendinden imzalı bir sertifika kabul edilene kadar, tarayıcı bir durum kodu için olanlar da dahil olmak üzere tüm istekleri kilitler. Tarayıcı (kodlanmışsa) güvensiz bir yanıt için kendi durum kodunu geri gönderebilir, ancak bu gerçekten hiçbir şeye yardımcı olmaz ve o zaman bile, tarayıcı uyumluluğuyla ilgili sorunlarınız olur (chrome / firefox / IE farklı standartlara sahip. .. bir kere daha)

Asıl sorunuz, sunucunuzun durumunu kabul edilmeyen bir sertifikaya sahip olmak arasında kontrol etmek olduğu için, böyle standart bir HTTP isteğinde bulunamaz mısınız?

isUp = false;
isAccepted = false;

var isUpRequest = new XMLHttpRequest();
isUpRequest.open('GET', "http://localhost/custom/server/", true); //note non-ssl port
isUpRequest.onload = function() {
    isUp = true;
    var isAcceptedRequest = new XMLHttpRequest();
    isAcceptedRequest.open('GET', "https://localhost/custom/server/", true); //note ssl port
    isAcceptedRequest.onload = function() {
        console.log("Server is up and certificate accepted");
        isAccepted = true;
    }
    isAcceptedRequest.onerror = function() {
        console.log("Server is up and certificate is not accepted");
    }
    isAcceptedRequest.send();
};
isUpRequest.onerror = function() {
    console.log("Server is down");
};
isUpRequest.send();

Bunun için sunucu bağlantısını doğrulamak için fazladan bir istek gerekir, ancak işi ortadan kaldırma süreciyle tamamlaması gerekir. Yine de huysuz hissediyor ve ben iki katına çıkan talebin büyük bir hayranı değilim.


7
Cevabın tamamını okudum ve bunun işe yarayacağını pek sanmıyorum. Her iki sunucum da HTTPS çalıştırıyor, yani bir HTTP sunucusuna bir istek yaptığım anda, tarayıcı bunu hemen iptal edecek, çünkü bir HTTPS sunucusundan bir HTTP sunucusuna ajax istekleri yapamazsınız
taxicala

11

@ Schultzie'nin cevabı oldukça yakın, ancak açıkça http- genel olarak - httpstarayıcı ortamında işe yaramayacak .

Yine de yapabileceğiniz şey, sizin adınıza istekte bulunmak için bir ara sunucu (proxy) kullanmaktır. Proxy, httpisteği httpskaynağından yönlendirmeye veya kendinden imzalı kaynaklardan içerik yüklemeye izin vermelidir .

Uygun sertifikaya sahip kendi sunucunuza sahip olmak, sizin durumunuzda büyük olasılıkla aşırılıktır - çünkü bu ayarı kendinden imzalı sertifikalı makine yerine kullanabilirsiniz - ancak orada çok sayıda anonim açık proxy hizmeti vardır.

Yani aklıma gelen iki yaklaşım:

  1. ajax isteği - böyle bir durumda proxy'nin uygun CORS ayarlarını kullanması gerekir
  2. iframe kullanımı - komut dosyanızı (muhtemelen html'ye sarılmış) proxy aracılığıyla bir iframe içine yüklersiniz. Komut dosyası yüklendikten sonra, kendisine bir mesaj gönderir .parentWindow. Pencereniz bir mesaj aldıysa, sunucunun çalıştığından (veya daha doğrusu bir saniyeden kısa bir süre önce çalıştığından) emin olabilirsiniz.

Yalnızca yerel ortamınızla ilgileniyorsanız, chrome'u --disable-web-securitybayrakla çalıştırmayı deneyebilirsiniz .


Başka bir öneri: Orada daha fazla bilgi olup olmadığını öğrenmek için programlı olarak bir görüntü yüklemeyi denediniz mi?


1

Check out jQuery.ajaxError () den referansı Alınan: jQuery AJAX Hata İşleme (HTTP Durum Kodları) Bu HTTP veya HTTPS üzerinden yollardan herhangi sayıda işleyebilir küresel Ajax hataları yakalar:

if (jqXHR.status == 501) {
//insecure response
} else if (jqXHR.status == 102) {
//connection refused
}

Bu, ajax'ı benim yaptığım şekilde yapmakla aynıdır, ancak hata yanıtlarını tek bir yerde merkezileştirmek.
taxicala

1
Mesele şu ki, sorun göründüğü için ajax çağrısı yapıldığında sertifikanın yüklenmemiş olmasıdır. Herhangi yolları :) cevapları bulmakta gl
Varshaan

2
Hayır, sorun şu ki, sertifikayı kabul etmek zorunda kalmakla sunucunun kapatılıp kapatılmadığını bilmek arasındaki farkı belirlemek istiyorum.
taxicala

1
Hem bağlantı reddedildiğinde hem de sertifika güvenilir olmadığında, bu yanıtta açıklandığı gibi qXHR.status == 102 veya 501 değil, aynı jqXHR.status = 0 (ve jqXHR.readyState = 0) alıyorum.
anre

1

Maalesef günümüz tarayıcı XHR API'si, tarayıcının "güvensiz yanıt" nedeniyle bağlanmayı reddettiğinde ve ayrıca web sitesinin HTTP / SSL sertifikasına güvenmediğinde açık bir gösterge sağlamamaktadır.

Ancak bu problemin etrafında yollar var.

Tarayıcının HTTP / SSL sertifikasına ne zaman güvenmediğini belirlemek için bulduğum bir çözüm, önce bir XHR hatası oluşup oluşmadığını tespit etmek ( error()örneğin jQuery geri aramayı kullanarak ), ardından XHR çağrısının bir 'https'ye olup olmadığını kontrol etmektir. : // 'URL ve ardından XHR'nin readyState0 olup olmadığını kontrol edin; bu, XHR bağlantısının henüz açılmadığı anlamına gelir (bu, tarayıcı sertifikayı beğenmediğinde olur).

Bunu yaptığım kod burada: https://github.com/maratbn/RainbowPayPress/blob/e9e9472a36ced747a0f9e5ca9fa7d96959aeaf8a/rainbowpaypress/js/le_requirejs/public/model_info__transaction_details.js#L88


1

Şu anda bu hata mesajlarını tespit etmenin bir yolu olduğunu sanmıyorum, ancak yapabileceğiniz bir hack, uygulama sunucunuzun önünde nginx gibi bir sunucu kullanmaktır, böylece uygulama sunucusu çalışmadığında kötü bir 502JS'de tespit edebileceğiniz durum kodlu nginx'ten ağ geçidi hatası . Aksi takdirde, sertifika geçersizse, yine de aynı genel hatayı alırsınız statusCode = 0.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.