I'm menggunakan $.post()
untuk memanggil servlet menggunakan Ajax dan kemudian menggunakan HTML yang dihasilkan fragmen untuk mengganti div
elemen dalam buku's halaman saat ini. Namun, jika sesi kali keluar, server mengirimkan mengarahkan petunjuk untuk mengirim pengguna ke halaman login. Dalam hal ini, jQuery adalah mengganti div
elemen dengan isi dari halaman login, memaksa pengguna's mata untuk menyaksikan adegan langka memang.
Bagaimana saya dapat mengelola mengarahkan direktif dari panggilan Ajax dengan jQuery 1.2.6?
Saya membaca pertanyaan ini dan menerapkan pendekatan yang telah dikemukakan mengenai pengaturan respon kode status HTTP untuk 278 dalam rangka untuk menghindari browser transparan penanganan pengalihan. Meskipun ini bekerja, saya sedikit puas karena itu adalah sedikit hack.
Setelah lebih menggali di sekitar, aku membuang pendekatan ini dan digunakan JSON. Dalam hal ini, semua tanggapan terhadap permintaan AJAX memiliki kode status 200 dan tubuh respon berisi objek JSON yang dibangun pada server. JavaScript pada klien kemudian dapat menggunakan objek JSON untuk memutuskan apa yang perlu dilakukan.
Saya punya masalah yang sama dengan anda. Saya melakukan permintaan AJAX yang memiliki 2 kemungkinan respon: salah satu yang pengalihan browser ke halaman baru dan salah satu yang menggantikan ada form HTML pada halaman saat ini dengan yang baru. Kode jQuery untuk melakukan hal ini mirip seperti:
$.ajax({
type: "POST",
url: reqUrl,
data: reqBody,
dataType: "json",
success: function(data, textStatus) {
if (data.redirect) {
// data.redirect contains the string URL to redirect to
window.location.href = data.redirect;
} else {
// data.form contains the HTML for the replacement form
$("#myform").replaceWith(data.form);
}
}
});
Objek JSON "data" ini dibangun pada server memiliki 2 anggota: data.mengarahkan
dan data.bentuk
. Saya menemukan pendekatan ini akan jauh lebih baik.
Saya memecahkan masalah ini dengan:
publik ActionResult Index(){ jika (!HttpContext.Pengguna.Identitas.IsAuthenticated) { HttpContext.Respon.AddHeader("REQUIRES_AUTH","1"); } return View(); }
ajaxSuccess
acara dan memeriksa untuk melihat jika header yang ada:$(document).ajaxSuccess(function(event, permintaan, pengaturan) { if (permintaan.getResponseHeader('REQUIRES_AUTH') === '1') { jendela.lokasi = '/'; } });
Tidak ada browser yang menangani 301 dan 302 tanggapan dengan benar. Dan pada kenyataannya standar bahkan mengatakan mereka harus menangani mereka "secara transparan" yang adalah sakit kepala BESAR bagi Ajax Perpustakaan vendor. Di Ra-Ajax kita dipaksa menggunakan respon HTTP status code 278 (hanya beberapa "yang tidak terpakai" sukses code) untuk menangani transparan pengalihan dari server...
Ini benar-benar mengganggu saya, dan jika ada orang di sini memiliki beberapa "menarik" di W3C saya akan menghargai bahwa anda bisa membiarkan W3C tahu bahwa kita benar-benar perlu untuk menangani 301 dan 302 kode diri kita sendiri...! ;)
Solusi yang akhirnya dilaksanakan adalah untuk menggunakan pembungkus untuk fungsi callback Ajax call dan di bungkus memeriksa keberadaan elemen tertentu pada HTML kembali chunk. Jika unsur itu ditemukan kemudian bungkusnya dieksekusi pengalihan. Jika tidak, pembungkus diteruskan panggilan sebenarnya fungsi callback.
Misalnya, kita pembungkus fungsi adalah sesuatu seperti:
function cbWrapper(data, funct){
if($("#myForm", data).length > 0)
top.location.href="login.htm";//redirection
else
funct(data);
}
Kemudian, ketika membuat Ajax panggilan kita menggunakan sesuatu seperti:
$.post("myAjaxHandler",
{
param1: foo,
param2: bar
},
function(data){
cbWrapper(data, myActualCB);
},
"html"
);
Ini bekerja untuk kita karena semua panggilan Ajax selalu kembali HTML dalam elemen DIV yang kita gunakan untuk menggantikan suatu bagian dari halaman. Juga, kita hanya perlu mengarahkan ke halaman login.
Saya suka Timmerz's metode dengan sedikit perasan lemon. Jika anda pernah mendapatkan kembali contentType dari text/html bila anda're mengharapkan JSON, anda kemungkinan besar dialihkan. Dalam kasus saya, saya hanya cukup reload halaman, dan itu akan dialihkan ke halaman login. Oh, dan periksa bahwa jqXHR status 200, yang tampaknya konyol, karena anda berada dalam fungsi kesalahan, kan? Jika tidak, sah kesalahan kasus akan memaksa berulang ulang (oops)
$.ajax(
error: function (jqXHR, timeout, message) {
var contentType = jqXHR.getResponseHeader("Content-Type");
if (jqXHR.status === 200 && contentType.toLowerCase().indexOf("text/html") >= 0) {
// assume that our login has expired - reload our current page
window.location.reload();
}
});
Gunakan tingkat rendah $.ajax()
call:
$.ajax({
url: "/yourservlet",
data: { },
complete: function(xmlHttp) {
// xmlHttp is a XMLHttpRquest object
alert(xmlHttp.status);
}
});
Coba ini untuk redirect:
if (xmlHttp.code != 200) {
top.location.href = '/some/other/page';
}
Saya hanya ingin berbagi pendekatan saya seperti ini, mungkin itu bisa membantu seseorang:
Pada dasarnya saya termasuk JavaScript modul yang menangani otentikasi hal-hal seperti menampilkan username dan juga hal ini penanganan redirect ke halaman login.
Skenario saya: pada dasarnya Kita memiliki sebuah server ISA di antara yang mendengarkan semua permintaan dan merespon dengan 302 dan lokasi header untuk halaman login.
Di JavaScript saya modul saya pendekatan awal adalah sesuatu seperti
$(document).ajaxComplete(function(e, xhr, settings){
if(xhr.status === 302){
//check for location header and redirect...
}
});
Masalah (seperti yang banyak di sini yang telah disebutkan itu) adalah bahwa browser menangani redirect dengan sendirinya karenanya saya ajaxComplete
callback punya tidak pernah disebut, tapi bukan aku punya respon sudah diarahkan halaman Login yang jelas adalah status 200
. Masalah: bagaimana cara mendeteksi apakah sukses 200 respon anda yang sebenarnya halaman login atau hanya beberapa lainnya sewenang-wenang halaman??
Karena saya tidak mampu menangkap 302 redirect tanggapan, saya menambahkan LoginPage
header pada halaman login yang berisi url dari halaman login itu sendiri. Dalam modul yang saya dengar untuk header dan melakukan redirect:
if(xhr.status === 200){
var loginPageRedirectHeader = xhr.getResponseHeader("LoginPage");
if(loginPageRedirectHeader && loginPageRedirectHeader !== ""){
window.location.replace(loginPageRedirectHeader);
}
}
...dan bekerja seperti pesona :). Anda mungkin bertanya-tanya mengapa saya sertakan url di LoginPage
header...nah pada dasarnya karena saya tidak menemukan cara untuk menentukan url GET
yang dihasilkan dari lokasi otomatis redirect dari xhr
objek...
Saya tahu topik ini sudah tua, tapi saya'll belum memberikan pendekatan lain I've ditemukan dan dijelaskan sebelumnya di sini. Pada dasarnya saya'm menggunakan ASP.MVC dengan WIF (tapi ini tidak benar-benar penting untuk konteks topik ini - jawaban yang memadai tidak peduli di mana kerangka kerja yang digunakan. Petunjuk tetap tidak berubah - berurusan dengan isu-isu yang berkaitan dengan kegagalan otentikasi saat melakukan permintaan ajax).
Pendekatan yang ditunjukkan di bawah ini dapat diterapkan untuk semua permintaan ajax out of the box (jika mereka tidak mendefinisikan beforeSend acara yang jelas).
$.ajaxSetup({
beforeSend: checkPulse,
error: function (XMLHttpRequest, textStatus, errorThrown) {
document.open();
document.write(XMLHttpRequest.responseText);
document.close();
}
});
Sebelum ajax permintaan ini dilakukan CheckPulse
method dipanggil (controller metode yang dapat sesuatu yang sederhana):
[Authorize]
public virtual void CheckPulse() {}
Jika pengguna tidak disahkan (token telah berakhir) metode tersebut tidak dapat diakses (dilindungi oleh Otorisasi
atribut). Karena kerangka menangani otentikasi, sementara token berakhir, menempatkan status http 302 untuk respon. Jika anda don't ingin browser anda untuk menangani 302 tanggapan secara transparan, menangkapnya di Global.asax dan perubahan respon status - misalnya untuk 200 OK. Selain itu, menambahkan header, yang menginstruksikan anda untuk proses respon tersebut dengan cara khusus (kemudian di sisi klien):
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 302
&& (new HttpContextWrapper(Context)).Request.IsAjaxRequest())
{
Context.Response.StatusCode = 200;
Context.Response.AddHeader("REQUIRES_AUTH", "1");
}
}
Akhirnya pada sisi klien memeriksa seperti header. Jika saat ini - full pengalihan ke halaman logon harus dilakukan (dalam kasus saya jendela.lokasi
diganti dengan url dari permintaan yang ditangani secara otomatis oleh framework).
function checkPulse(XMLHttpRequest) {
var location = window.location.href;
$.ajax({
url: "/Controller/CheckPulse",
type: 'GET',
async: false,
beforeSend: null,
success:
function (result, textStatus, xhr) {
if (xhr.getResponseHeader('REQUIRES_AUTH') === '1') {
XMLHttpRequest.abort(); // terminate further ajax execution
window.location = location;
}
}
});
}
Saya menyelesaikan masalah ini seperti ini:
Tambahkan middleware untuk proses respon, jika itu adalah untuk mengarahkan permintaan ajax, perubahan respon terhadap respon normal dengan url redirect.
class AjaxRedirect(object):
def process_response(self, request, response):
if request.is_ajax():
if type(response) == HttpResponseRedirect:
r = HttpResponse(json.dumps({'redirect': response['Location']}))
return r
return response
Kemudian di ajaxComplete, jika respon mengandung redirect, itu harus menjadi mengarahkan, sehingga mengubah browser's lokasi.
$('body').ajaxComplete(function (e, xhr, settings) {
if (xhr.status == 200) {
var redirect = null;
try {
redirect = $.parseJSON(xhr.responseText).redirect;
if (redirect) {
window.location.href = redirect.replace(/\?.*$/, "?next=" + window.location.pathname);
}
} catch (e) {
return;
}
}
}
Saya pikir cara yang lebih baik untuk menangani hal ini adalah dengan memanfaatkan yang ada protokol HTTP kode respon, secara khusus 401 tidak Sah
.
Berikut adalah bagaimana saya soal itu:
$('body').bind('ajaxSuccess',function(event,permintaan,pengaturan){ jika (401 == permintaan.status){ jendela.lokasi = '/users/login'; } }).bind('ajaxError',function(event,permintaan,pengaturan){ jika (401 == permintaan.status){ jendela.lokasi = '/users/login'; } });
IMO ini lebih generik dan anda tidak menulis beberapa kustom baru spec/header. Anda juga tidak harus mengubah apapun yang ada ajax panggilan.
Edit: Per @Rob's komentar di bawah ini, 401 (HTTP status code untuk otentikasi kesalahan) harus menjadi indikator. Lihat https://stackoverflow.com/questions/3297048/403-forbidden-vs-401-unauthorized-http-responses untuk lebih detail. Dengan itu dikatakan beberapa kerangka web menggunakan 403 untuk otentikasi DAN otorisasi kesalahan - jadi beradaptasi sesuai. Terima Kasih Rob.
Sebagian besar diberikan solusi menggunakan pemecahan masalah, menggunakan tambahan header atau inappropiate HTTP code. Solusi-solusi tersebut akan paling mungkin bekerja tetapi merasa sedikit 'hacky'. I've datang dengan solusi lain.
Kami're menggunakan WIF yang dikonfigurasi untuk mengarahkan (passiveRedirectEnabled="benar") pada 401 respon. Redirect ini berguna ketika menangani permintaan normal tetapi tidak't bekerja untuk permintaan AJAX (karena browser tidak't mengeksekusi 302/redirect).
Menggunakan kode berikut di global anda.asax anda dapat menonaktifkan redirect untuk permintaan AJAX:
void WSFederationAuthenticationModule_AuthorizationFailed(object sender, AuthorizationFailedEventArgs e)
{
string requestedWithHeader = HttpContext.Current.Request.Headers["X-Requested-With"];
if (!string.IsNullOrEmpty(requestedWithHeader) && requestedWithHeader.Equals("XMLHttpRequest", StringComparison.OrdinalIgnoreCase))
{
e.RedirectToIdentityProvider = false;
}
}
Hal ini memungkinkan anda untuk kembali 401 tanggapan untuk permintaan AJAX, yang javascript anda kemudian dapat menangani dengan reload halaman. Reload halaman akan membuang 401 yang akan ditangani oleh WIF (dan WIF akan mengarahkan pengguna ke halaman login).
Contoh javascript untuk menangani kesalahan 401:
$(document).ajaxError(function (event, jqxhr, settings, exception) {
if (jqxhr.status == 401) { //Forbidden, go to login
//Use a reload, WIF will redirect to Login
location.reload(true);
}
});
Masalah ini mungkin muncul kemudian menggunakan ASP.NET MVC RedirectToAction metode. Untuk mencegah bentuk menampilkan respon div anda hanya dapat melakukan beberapa jenis ajax filter respon untuk incomming tanggapan dengan $.ajaxSetup. Jika respon berisi MVC pengalihan anda dapat mengevaluasi ekspresi JS samping. Contoh kode untuk JS di bawah ini:
$.ajaxSetup({
dataFilter: function (data, type) {
if (data && typeof data == "string") {
if (data.indexOf('window.location') > -1) {
eval(data);
}
}
return data;
}
});
Jika data adalah: "jendela.lokasi = '/Akun/Login'," di atas filter yang akan menangkap itu dan mengevaluasi untuk membuat pengalihan bukannya membiarkan data yang akan ditampilkan.
Solusi lain yang saya temukan (terutama berguna jika anda ingin mengatur global perilaku) adalah dengan menggunakan $.ajaxsetup()
metode bersama-sama dengan status
property. Seperti orang lain menunjukkan, don't menggunakan redirect statuscode (3xx
), bukan menggunakan 4xx
statuscode dan menangani mengarahkan client-side.
$.ajaxSetup({
statusCode : {
400 : function () {
window.location = "/";
}
}
});
Ganti 400
dengan status yang anda inginkan untuk menangani. Seperti telah disebutkan tidak Sah 401
bisa menjadi ide yang baik. Saya menggunakan 400
karena itu's sangat tidak spesifik dan dapat saya gunakan 401
untuk kasus yang lebih spesifik (seperti salah login). Jadi, bukan mengarahkan langsung backend anda harus kembali 4xx
error-code-saat sesi habis dan anda anda menangani mengarahkan client-side. Bekerja sempurna bagi saya bahkan dengan kerangka kerja seperti backbone.js
Menempatkan bersama-sama apa Vladimir Prudnikov dan Thomas Hansen mengatakan:
jika permintaan.is_ajax(): respon.status_code = 278
Hal ini membuat browser mengobati respon sebagai suatu keberhasilan, dan Javascript.
$('#saya-bentuk').submit(function(event){
acara.preventDefault(); var pilihan = { url: $(this).attr('action'), tipe: 'POST', lengkap: function(response, textStatus) { jika (respon.status == 278) { window.lokasi = respon.getResponseHeader('Lokasi') } else { ... kode anda di sini ... } }, data: $(this).cerita bersambung(), }; $.ajax(pilihan); });
Saya memiliki solusi sederhana yang bekerja untuk saya, tidak ada server perubahan kode yang diperlukan...hanya menambahkan sdt pala...
$(document).ready(function ()
{
$(document).ajaxSend(
function(event,request,settings)
{
var intercepted_success = settings.success;
settings.success = function( a, b, c )
{
if( request.responseText.indexOf( "<html>" ) > -1 )
window.location = window.location;
else
intercepted_success( a, b, c );
};
});
});
Aku memeriksa kehadiran tag html, tetapi anda dapat mengubah indexOf untuk mencari apapun string unik yang ada di halaman login anda...
Mencoba
$(document).ready(function () {
if ($("#site").length > 0) {
window.location = "<%= Url.Content("~") %>" + "Login/LogOn";
}
});
Meletakkannya di halaman login. Jika itu dimuat dalam sebuah div pada halaman utama, itu akan mengarahkan til halaman login. "#situs" adalah id div yang terletak pada semua halaman kecuali halaman login.
<script>
function showValues() {
var str = $("form").serialize();
$.post('loginUser.html',
str,
function(responseText, responseStatus, responseXML){
if(responseStatus=="success"){
window.location= "adminIndex.html";
}
});
}
</script>
Sementara jawaban yang tampaknya bekerja untuk orang-orang jika anda're menggunakan Semi Keamanan saya telah menemukan memperpanjang LoginUrlAuthenticationEntryPoint dan menambahkan kode tertentu untuk menangani AJAX lebih kuat. Sebagian besar contoh mencegat semua mengarahkan tidak hanya kegagalan otentikasi. Hal ini tidak diinginkan untuk proyek yang saya kerjakan. Anda mungkin merasa perlu untuk juga memperpanjang ExceptionTranslationFilter dan menimpa "sendStartAuthentication" metode untuk menghapus cache langkah jika anda don't ingin gagal AJAX permintaan cache.
Contoh AjaxAwareAuthenticationEntryPoint:
public class AjaxAwareAuthenticationEntryPoint extends
LoginUrlAuthenticationEntryPoint {
public AjaxAwareAuthenticationEntryPoint(String loginUrl) {
super(loginUrl);
}
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
if (isAjax(request)) {
response.sendError(HttpStatus.UNAUTHORIZED.value(), "Please re-authenticate yourself");
} else {
super.commence(request, response, authException);
}
}
public static boolean isAjax(HttpServletRequest request) {
return request != null && "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
}
}
Mari saya hanya mengutip lagi masalah seperti yang dijelaskan oleh @Steg
saya punya masalah yang sama dengan anda. Saya melakukan permintaan ajax yang memiliki 2 kemungkinan respon: salah satu yang mengarahkan browser ke halaman baru dan salah satu yang menggantikan yang sudah ada form HTML pada halaman saat ini dengan yang baru satu.
IMHO ini adalah tantangan nyata dan akan secara resmi diperpanjang untuk saat ini HTTP standar.
Saya percaya baru Http Standar akan menggunakan status baru-kode.
artinya: saat ini 301/302
memberitahu browser untuk pergi dan mengambil isi ini permintaan baru lokasi
.
Di extended standar, itu akan mengatakan bahwa jika respon status: 308
(hanya contoh), maka browser harus mengarahkan halaman utama untuk lokasi
yang disediakan.
Yang sedang berkata; aku'm cenderung sudah meniru ini perilaku perilaku, dan oleh karena itu ketika sebuah dokumen.redirect yang dibutuhkan, saya memiliki server merespon seperti:
status: 204 No Content
x-status: 308 Document Redirect
x-location: /login.html
Ketika JS mendapat "status: 204
", memeriksa keberadaan dari x-status: 308
header, dan dokumen.redirect ke halaman yang disediakan di lokasi
header.
Apakah ini masuk akal bagimu?