Bagaimana mencegah permintaan ajax mengikuti pengalihan menggunakan jQuery

103

Saya menggunakan fungsi jQuery ajax untuk mengakses layanan web, tetapi server, alih-alih mengembalikan respons dengan kode status yang menjelaskan masalah, permintaan tersebut dialihkan ke halaman dengan header 200, yang menjelaskan masalahnya. Saya tidak dapat membuat perubahan apa pun untuk ini, jadi saya harus menyelesaikannya pada klien entah bagaimana caranya.

Contoh: Permintaan pergi ke beberapa URL yang tidak ditemukan, jadi saya menerima 302 Redirect ke lokasi lain. Permintaan baru dikirim, dan saya menerima 200 OK, sehingga mencegah kesalahan panggilan balik untuk diaktifkan.

Adakah cara agar saya dapat mencegah permintaan ajax mengikuti pengalihan dan sebagai gantinya memanggil callback, sebaiknya metode kesalahan. Atau, apakah mungkin untuk mendeteksi jika pengalihan telah terjadi di klien?

Jørgen
sumber
8
Aneh bahwa backend Anda melaporkan 302 untuk tidak ditemukan, bukan 404.
Jake Feasel
Kemungkinan duplikat dari Cegah pengalihan Xmlhttprequest
pengguna

Jawaban:

96

Saya menemukan pertanyaan Anda menarik, tetapi masalah secara keseluruhan tampaknya lebih merupakan kesalahpahaman. Setidaknya saya akan mencoba menjelaskan pemahaman saya tentang masalah tersebut.

Pengalihan diam (transparan) adalah bagian dari XMLHttpRequestspesifikasi (lihat di sini terutama kata-kata "... secara transparan ikuti pengalihan ..."). Standar hanya menyebutkan bahwa agen pengguna (browser web) dapat mencegah atau memberi tahu beberapa jenis pengalihan otomatis, tetapi itu bukan bagian dari XMLHttpRequest. Ini adalah bagian dari konfigurasi klien HTTP (konfigurasi OS) atau konfigurasi browser web. Jadi jQuery.ajaxtidak dapat memiliki opsi apa pun di mana Anda dapat mencegah pengalihan.

Anda dapat melihat bahwa pengalihan HTTP adalah bagian dari protokol HTTP dan bukan bagian dari XMLHttpRequest. Jadi ini ada di level abstraksi lain atau tumpukan jaringan. Misalnya data dari XMLHttpRequestdapat diambil dari proxy HTTP atau dari cache browser lokal, dan itu adalah bagian dari protokol HTTP. Sebagian besar server yang menyediakan data dan bukan klien dapat memengaruhi caching.

Anda dapat membandingkan persyaratan dari pertanyaan Anda dengan persyaratan untuk mencegah perubahan alamat IP server web atau perubahan rute IP selama komunikasi. Semua hal bisa menarik dalam beberapa skenario, tetapi ada bagian dari tumpukan komunikasi tingkat lain dan tidak dapat dikelola oleh jQuery.ajaxatau XMLHttpRequest.

The XMLHttpRequeststandar mengatakan bahwa konfigurasi klien dapat memiliki pilihan yang mencegah pengalihan. Dalam kasus "Microsoft world", yang lebih saya ketahui, Anda dapat melihat fungsi WinHttpSetOption yang dapat digunakan untuk mengatur WINHTTP_OPTION_DISABLE_FEATUREopsi dengan WINHTTP_DISABLE_REDIRECTSnilai. Cara lain adalah penggunaan WINHTTP_OPTION_REDIRECT_POLICYopsi dengan WINHTTP_OPTION_REDIRECT_POLICY_NEVERnilai. Satu lagi fitur yang dapat digunakan di Windows adalah fungsi WinHttpSetStatusCallback yang dapat mengatur fungsi panggilan balik menerima beberapa pemberitahuan seperti WINHTTP_CALLBACK_FLAG_REDIRECT.

Jadi mungkin saja untuk mengimplementasikan persyaratan Anda secara umum, tetapi solusinya mungkin tidak terlepas dari sistem operasi atau browser web dan tidak berada pada level jQuery.ajaxatau XMLHttpRequest.

Oleg
sumber
2
Jawaban luar biasa dengan wawasan luar biasa! Saya memiliki beberapa pengalaman dengan curl, di mana Anda dapat mengatur bendera yang sama seperti yang Anda sebutkan. Saya berharap instruksi seperti itu dapat diteruskan ke browser, tetapi dari jawaban Anda, saya memahami bahwa perilaku yang diharapkan adalah mengikuti pengalihan seolah-olah permintaan awal dikirim ke lokasi yang ditentukan oleh server.
Jørgen
@ Jørgen: Sama-sama! Dalam kebanyakan skenario, pengalihan tidak menjadi masalah sama sekali. Anda tidak menjelaskan konteks di mana Anda menggunakan jQuery.ajax dan apakah Anda memiliki kendali penuh atas server web yang Anda kirimi permintaan. Jadi sulit memberi Anda nasihat lain yang benar-benar dapat menyelesaikan masalah Anda.
Oleg
Saya tidak mengontrol sisi server, saya khawatir. Saya kira pilihan terbaik saya adalah menganalisis atau memvalidasi konten tanggapan.
Jørgen
@ Jørgen: Mengapa pengalihan menjadi masalah dalam kasus Anda? Jika server memindahkan beberapa halaman di lokasi lain untuk sementara atau secara permanen, ini dapat mengarahkan permintaan awal Anda ke lokasi baru. Ini akan baik-baik saja. Administrator dapat mengkonfigurasi server web untuk melakukan pengalihan misalnya selama operasi pemulihan di server atau pekerjaan dukungan lainnya. Jika Anda menanyakan server dengan URL yang memiliki DNS, administrator dapat mengubah pemetaan IP ke server lain. Dia dapat melakukan pengalihan HTTP dengan cara yang sama seperti konfigurasi ulang DNS. Apa masalahmu?
Oleg
Masalah saya adalah pengalihan menuju ke halaman kesalahan umum. Saya tahu server harus disiapkan secara berbeda, tetapi untuk saat ini saya perlu menemukan solusi untuk situasi ini sebagaimana adanya.
Jørgen
23

Saya tidak percaya itu mungkin. Library yang mendasari (XHR) membuat permintaan baru secara transparan. Karena itu, apa yang telah saya lakukan dalam situasi ini (biasanya jenis kesepakatan waktu tunggu sesi yang membawa saya ke halaman login) adalah mengirim kembali header respons kustom. Saya juga telah menyiapkan penangan ajax global yang memeriksa keberadaan header itu, dan merespons dengan tepat saat ada (misalnya, mengarahkan seluruh halaman ke layar login).

Jika Anda tertarik, berikut kode jQuery yang harus saya perhatikan untuk tajuk khusus itu:

/* redirects main window when AJAX request indicates that the session has expired on the backend. */
function checkSession(event, xhr, ajaxOptions)
{
    if (xhr.readyState == 4)
    {
        if(xhr.getResponseHeader("Login-Screen") != null && xhr.getResponseHeader("Login-Screen").length)
        {
            window.location.href='sessionExpired.html'; //whatever
        }
    }
}

$(document).ajaxComplete(checkSession)
Jake Feasel
sumber
1
Terima kasih, saya rasa saya harus puas dengan pendekatan serupa, menganalisis tanggapannya.
Jørgen
11

Saya menemukan fitur untuk memeriksa apakah panggilan Anda telah dialihkan. Ini xhr.state (): jika "ditolak" maka pengalihan terjadi.

Contoh dengan panggilan balik sukses:

request.success(function(data, textStatus, xhr)
{
    if(xhr.state() == "resolved")
    {
        //no redirection
    }
    if(xhr.state() == "rejected")
    {
        //redirection
    }
});

Contoh dengan error callback:

request.error(function(xhr, textStatus)
{
    if (xhr.state() == "rejected")
    {
        //redirection
        location.href = "loginpage";
    } else
    {
        //some other error happened
        alert("error");
    }
});
Takman
sumber
1
Tip dalam jawaban Anda sangat membantu kami menyelesaikan berbagai hal. Demi catatan yang akan membantu orang lain, kami memiliki Portal WebSphere yang keamanannya terintegrasi dengan SiteMinder. Kami memiliki portlet yang membutuhkan panggilan Ajax ke url sumber daya dan ketika waktu habis, pengalihan transparan tersebut terjadi tetapi kami tidak dapat menangani cara mengarahkan ke halaman login. Memeriksa jqXHR.state () yang "ditolak" pasti membantu. Terima kasih banyak lagi.
Uresh Kuruhuri
Penemuan yang bagus, namun bisa saja ada kesalahan positif karena status "ditolak" dapat dipicu bahkan jika janji ditolak dan tidak hanya saat pengalihan. jQuery menjelaskan kapan status "ditolak" dikirim api.jquery.com/deferred.state
Nitin
1

Saya tidak mungkin menambahkan kearifan berwawasan dari pembuat kode sebelumnya yang telah menanggapi, tetapi saya akan menambahkan kasus spesifik yang mungkin berguna untuk diketahui orang lain.

Saya menemukan 302 pengalihan diam ini dalam konteks SharePoint. Saya memiliki beberapa kode klien Javascript sederhana yang mengirim ping ke sub-situs SharePoint, dan jika menerima respons HTTP 200, ia pindah ke situs itu, melalui window.location. Jika menerima hal lain, ini memberi pengguna pemberitahuan bahwa situs tersebut tidak ada.

Namun, dalam kasus di mana situs tersebut ada tetapi pengguna tidak memiliki izin, SharePoint secara diam-diam mengalihkan ke halaman AccessDenied.aspx. SharePoint telah melakukan jabat tangan otentikasi HTTP 401 di tingkat server / pertanian - pengguna memiliki akses ke SharePoint. Tetapi akses ke sub-situs ditangani, saya kira menggunakan semacam bendera database. Pengalihan diam-diam melewati klausa "lain" saya, jadi saya tidak bisa menampilkan kesalahan saya sendiri. Dalam kasus saya, ini bukan show-stopper - ini adalah perilaku yang dapat diprediksi secara konsisten. Tapi itu sedikit mengejutkan, dan saya belajar sesuatu tentang permintaan HTTP dalam prosesnya!

Chris van Hasselt
sumber
1

Saya tertarik pada hal yang sama dan tidak dapat menemukan state()metode yang disebutkan oleh Takman dan melakukan sedikit penggalian untuk diri saya sendiri. Demi orang-orang yang muncul di sini untuk mencari jawaban, inilah temuan saya:

Seperti yang dinyatakan beberapa kali, Anda tidak dapat mencegah pengalihan, tetapi Anda dapat mendeteksinya. Menurut MDN, Anda dapat menggunakan responseURLdari XMLHttpRequestObject, yang akan berisi URL final tempat tanggapan berasal, setelah semua pengalihan. Satu-satunya peringatan adalah bahwa itu tidak didukung oleh Internet Explorer (Edge memilikinya). Karena xhr/ jqXHRditeruskan ke success/ donefungsi jquery adalah perpanjangan dari aktual XMLHttpRequest, itu juga harus tersedia di sana.

Rialgar
sumber
0

Saya kira Anda menerima 200 respon karena kedua kalinya tidak ada pengalihan, karena halaman 404 tidak kedaluwarsa, itu disimpan di cache. Artinya, untuk kedua kalinya browser memberi Anda halaman dalam cache. Ada properti "cache" di ajax jquery. http://api.jquery.com/jQuery.ajax/

Anda harus menuliskannya ke "false"

netadictos.dll
sumber
0

Meskipun tidak mungkin menonaktifkan pengalihan lokasi yang mengikuti XmlHttpRequests , itu adalah saat menggunakan fetch () :

fetch('url', {redirect: manual});
cweiske.dll
sumber
Pengambilan tidak akan memberi tahu Anda apa itu URL yang dialihkan. Anda dapat menonaktifkan perilaku tersebut, tetapi "redirect: manual" tidak dimaksudkan untuk membiarkan pengguna menangani pengalihan itu sendiri yang memiliki nama maksud.
lcjury
-2

Saya tidak yakin apakah ini akan berlaku dalam kasus Anda, tetapi Anda dapat menulis kode untuk menanggapi kode status tertentu dalam fungsi AJAX -

$.ajax({
    url: '/admin/secret/data',
    type: 'POST',
    contentType: 'application/json; charset=utf-8',
    statusCode: {
        200: function (data) {
            alert('302: Occurred');
            // Bind the JSON data to the UI
        },
        401: function (data) {
            alert('401: Occurred');
            // Handle the 401 error here.
        }
    }
});
ipr101
sumber
9
Saya tidak berpikir ini berlaku karena OP mengatakan dia selalu mendapat kode status 200 karena pengalihan terjadi di latar belakang ..
Ya Barry
-4

Dalam header permintaan dalam kasus permintaan ajax Anda akan memiliki yang berikut ini

X-Requested-With    XMLHttpRequest

Dengan kriteria ini di sisi server Anda dapat memfilter permintaan.

Gfox
sumber
Dia ingin memeriksa tanggapan, bukan permintaan (yang sudah dia kendalikan)
Ya Barry
Mungkin Gfox menyarankan bahwa untuk permintaan ajax yang mengembalikan 3xx tidak ada gunanya, Anda dapat memfilter permintaan semacam ini dan mengembalikan 403 misalnya. ketika Anda memiliki situs web yang menyajikan halaman yang memerlukan otentikasi formulir dan halaman-halaman itu juga membuat panggilan ajax dan Anda ingin meletakkan logika otorisasi di satu tempat, maka bagi saya itu adalah jawaban yang valid.
maciejW