Rumah > hujung hadapan web > tutorial css > Dikatakan dengan pasti menghantar permintaan HTTP sebagai pengguna meninggalkan halaman

Dikatakan dengan pasti menghantar permintaan HTTP sebagai pengguna meninggalkan halaman

William Shakespeare
Lepaskan: 2025-03-14 10:06:09
asal
468 orang telah melayarinya

Dikatakan dengan pasti menghantar permintaan HTTP sebagai pengguna meninggalkan halaman

Dalam banyak kes, saya perlu menghantar permintaan HTTP yang mengandungi beberapa data untuk merekodkan apa yang pengguna lakukan, seperti menavigasi ke halaman lain atau mengemukakan borang. Pertimbangkan contoh ini, yang menghantar beberapa maklumat ke perkhidmatan luaran semasa mengklik pautan:

 <a href="https://www.php.cn/link/3cbfb2330b21840b385a45c958602663">Pergi ke halaman</a>

document.getElementById ('link'). AddEventListener ('klik', (e) => {
  Ambil ("/log", {
    Kaedah: "pos",
    tajuk: {
      "Kandungan-jenis": "Aplikasi/JSON"
    }, 
    badan: json.stringify ({
      Ada: "Data"
    })
  });
});
Salin selepas log masuk

Tidak ada yang sangat rumit di sini. Pautan berfungsi seperti biasa (saya tidak menggunakan e.preventDefault() ), tetapi sebelum tingkah laku itu berlaku, permintaan pos dicetuskan. Tidak perlu menunggu sebarang respons. Saya hanya mahu menghantarnya ke mana -mana perkhidmatan yang saya lawati.

Pada pandangan pertama, anda mungkin berfikir bahawa penjadualan permintaan disegerakkan, selepas itu kami akan terus menavigasi dari halaman, dan pelayan lain berjaya memproses permintaan tersebut. Tetapi ternyata ini tidak selalu berlaku.

Penyemak imbas tidak menjamin bahawa permintaan HTTP terbuka akan dikekalkan

Apabila peristiwa -peristiwa tertentu berlaku untuk menamatkan halaman dalam penyemak imbas, tidak ada jaminan bahawa permintaan HTTP yang diproses akan berjaya (lebih lanjut mengenai kitaran hayat halaman "penamatan" dan negeri -negeri lain). Kebolehpercayaan permintaan ini mungkin bergantung kepada beberapa faktor -sambungan rangkaian, prestasi aplikasi, dan juga konfigurasi perkhidmatan luaran itu sendiri.

Oleh itu, menghantar data pada momen-momen ini boleh jauh dari yang boleh dipercayai, dan jika anda bergantung pada log ini untuk membuat keputusan perniagaan sensitif data, mungkin ada masalah yang berpotensi penting.

Untuk menggambarkan ketidakpercayaan ini, saya menyediakan aplikasi ekspres kecil dengan halaman menggunakan kod di atas. Apabila pautan diklik, penyemak imbas menavigasi ke /other , tetapi sebelum ini berlaku, permintaan pos dikeluarkan.

Walaupun segala -galanya berlaku, saya membuka tab "Rangkaian" penyemak imbas saya dan menggunakan kelajuan sambungan "Slow 3G". Selepas halaman dimuat, saya membersihkan kayu balak dan semuanya kelihatan tenang:

Tetapi apabila anda mengklik pada pautan, perkara menjadi salah. Apabila navigasi berlaku, permintaan dibatalkan.

Ini meninggalkan kita hampir tidak dapat memastikan bahawa perkhidmatan luaran sebenarnya boleh mengendalikan permintaan. Untuk mengesahkan tingkah laku ini, ini juga berlaku apabila kita menggunakan window.location untuk menavigasi secara programatik:

 document.getElementById ('link'). AddEventListener ('klik', (e) => {
  E.PreventDefault ();

  // Permintaan itu telah beratur tetapi dibatalkan sejurus selepas navigasi berlaku.
  Ambil ("/log", {
    Kaedah: "pos",
    tajuk: {
      "Kandungan-jenis": "Aplikasi/JSON"
    },
    badan: json.stringify ({
      Beberapa: 'Data'
    }),
  });

  window.location = e.target.href;
});
Salin selepas log masuk

Permintaan yang belum selesai ini boleh ditinggalkan tanpa mengira bagaimana atau apabila navigasi berlaku dan apabila halaman aktif berakhir.

Mengapa ia dibatalkan?

Penyebab utama masalah ialah secara lalai, permintaan XHR (melalui fetch atau XMLHttpRequest ) adalah tak segerak dan tidak menyekat. Sebaik sahaja permintaan itu beratur, kerja sebenar permintaan itu dihantar ke API peringkat pelayar di latar belakang.

Ini hebat dari segi prestasi - anda tidak mahu permintaan itu mengambil benang utama. Tetapi ini juga bermakna bahawa apabila halaman memasuki keadaan "penamatan", mereka berisiko ditinggalkan dan tidak ada jaminan bahawa kerja latar belakang dapat diselesaikan. Inilah ringkasan Google mengenai keadaan kitaran hayat tertentu:

Sebaik sahaja halaman mula menyahpasang dan dibersihkan dari ingatan oleh penyemak imbas, ia berada dalam keadaan yang ditamatkan. Di negeri ini, tiada tugas baru tidak dapat dimulakan dan boleh ditamatkan jika tugas yang sedang berjalan berjalan terlalu lama.

Singkatnya, andaian reka bentuk penyemak imbas adalah bahawa apabila halaman ditutup, tidak perlu terus memproses sebarang proses latar belakang yang beratur.

Jadi, apakah pilihan kita?

Cara yang paling jelas untuk mengelakkan masalah ini adalah untuk melambatkan tindakan pengguna sebanyak mungkin sehingga permintaan itu mengembalikan respons. Pada masa lalu, ini dilakukan dengan salah dengan menggunakan bendera penyegerakan yang disokong dalam XMLHttpRequest . Tetapi dengan menggunakannya sepenuhnya menghalang benang utama, menyebabkan banyak masalah prestasi - saya telah menulis beberapa perkara mengenai perkara ini pada masa lalu - jadi idea ini tidak boleh dipertimbangkan. Malah, ia akan keluar dari platform (Chrome V80 telah mengeluarkannya).

Sebaliknya, jika anda akan mengambil pendekatan ini, lebih baik menunggu janji untuk menyelesaikan respons yang dikembalikan. Sebaik sahaja anda kembali, anda boleh melakukan tingkah laku dengan selamat. Menggunakan coretan kod sebelumnya kami, ini mungkin kelihatan seperti ini:

 document.getElementById ('link'). AddEventListener ('klik', async (e) => {
  E.PreventDefault ();

  // tunggu jawapan untuk kembali ...
  Tunggu ambil ("/log", {
    Kaedah: "pos",
    tajuk: {
      "Kandungan-jenis": "Aplikasi/JSON"
    },
    badan: json.stringify ({
      Beberapa: 'Data'
    }),
  });

  // ... dan kemudian menavigasi untuk pergi.
  window.location = e.target.href;
});
Salin selepas log masuk

Ini boleh melakukan pekerjaan itu, tetapi mempunyai beberapa kelemahan yang tidak remeh.

Pertama, ia memberi kesan kepada pengalaman pengguna dengan melambatkan berlakunya tingkah laku yang diperlukan. Mengumpul data analisis pasti memberi manfaat kepada perniagaan (dan kepada pengguna masa depan), tetapi itu jauh dari ideal kerana ia membuat pengguna semasa membayar untuk mencapai manfaat ini. Belum lagi, sebagai kebergantungan luaran, sebarang latensi atau isu prestasi lain dalam perkhidmatan itu sendiri akan dapat dilihat kepada pengguna. Sekiranya masa tamat dari perkhidmatan analisis anda menyebabkan pelanggan gagal menyelesaikan operasi bernilai tinggi, semua orang akan kalah.

Kedua, pendekatan ini tidak boleh dipercayai kerana pada mulanya bunyi, kerana beberapa tingkah laku penamatan tidak dapat ditangguhkan secara programatik. Sebagai contoh, e.preventDefault() tidak berguna dalam melambatkan pengguna untuk menutup tab penyemak imbas. Jadi, paling baik, ia hanya akan merangkumi pengumpulan data dari tindakan pengguna tertentu , tetapi tidak cukup untuk mempercayainya sepenuhnya.

Arahkan penyemak imbas untuk mengekalkan permintaan yang belum selesai

Syukurlah, kebanyakan pelayar mempunyai pilihan terbina dalam untuk mengekalkan permintaan HTTP yang belum selesai tanpa menjejaskan pengalaman pengguna.

Gunakan logo Keepalive Fetch

Jika bendera keepalive ditetapkan kepada true apabila menggunakan fetch() , permintaan yang sepadan masih terbuka walaupun halaman yang memulakan permintaan telah ditamatkan. Menggunakan contoh awal kami, ini akan menjadikan pelaksanaannya kelihatan seperti ini:

 <a href="https://www.php.cn/link/3cbfb2330b21840b385a45c958602663">Pergi ke halaman</a>

document.getElementById ('link'). AddEventListener ('klik', (e) => {
  Ambil ("/log", {
    Kaedah: "pos",
    tajuk: {
      "Kandungan-jenis": "Aplikasi/JSON"
    },
    badan: json.stringify ({
      Ada: "Data"
    }),
    Keepalive: Benar
  });
});
Salin selepas log masuk

Semasa mengklik pada pautan dan navigasi halaman berlaku, tiada pembatalan permintaan berlaku:

Sebaliknya, kita mendapat keadaan (tidak diketahui) semata -mata kerana halaman aktif tidak pernah menunggu sebarang respons yang diterima.

Kod satu baris sedemikian mudah untuk diperbaiki, terutamanya jika ia adalah sebahagian daripada API penyemak imbas biasa. Walau bagaimanapun, jika anda mencari pilihan yang lebih berpusat dengan antara muka yang lebih mudah, ada cara lain untuk melakukannya dengan sokongan penyemak imbas yang sama.

Gunakan Navigator.SendBeacon ()

Fungsi Navigator.sendBeacon() digunakan secara khusus untuk menghantar permintaan sehala (suar). Pelaksanaan asas adalah seperti berikut, yang menghantar jawatan dengan JSON yang berlapis dan Content-Type "teks/biasa":

 Navigator.SendBeacon ('/log', json.stringify ({
  Ada: "Data"
}));
Salin selepas log masuk

Tetapi API ini tidak membenarkan anda menghantar tajuk tersuai. Oleh itu, untuk menghantar data kami sebagai "Aplikasi/JSON", kita perlu membuat tweak kecil dan menggunakan gumpalan:

 <a href="https://www.php.cn/link/3cbfb2330b21840b385a45c958602663">Pergi ke halaman</a>

document.getElementById ('link'). AddEventListener ('klik', (e) => {
  const blob = blob baru ([json.stringify ({some: "data"})], {type: 'application/json; charset = utf-8'});
  Navigator.SendBeacon ('/log', gumpalan);
});
Salin selepas log masuk

Pada akhirnya, kami mendapat hasil yang sama - permintaan itu selesai walaupun selepas halaman dilayari. Tetapi ada beberapa perkara yang berlaku, yang mungkin menjadikannya lebih baik daripada fetch() : suar dihantar pada keutamaan yang rendah.

Untuk demonstrasi, inilah yang dipaparkan dalam tab Rangkaian apabila menggunakan kedua -dua fetch() dan sendBeacon() dengan keepalive :

Secara lalai, fetch() mendapat keutamaan "tinggi", manakala suar (dinyatakan sebagai "ping" jenis di atas) mempunyai keutamaan "terendah". Ini adalah perkara yang baik untuk permintaan yang tidak penting untuk fungsi halaman. Terus dari spesifikasi Beacon:

Spesifikasi ini mentakrifkan antara muka yang [...] meminimumkan persaingan sumber dengan operasi masa kritikal yang lain sambil memastikan bahawa permintaan tersebut masih diproses dan dihantar ke destinasi.

Dalam erti kata lain, sendBeacon() memastikan bahawa permintaannya tidak menghalang permintaan yang sangat penting untuk aplikasi dan pengalaman pengguna anda.

Sebutan kehormat atribut Ping

Perlu dinyatakan bahawa semakin banyak penyemak imbas menyokong atribut ping . Apabila dilampirkan pada pautan, ia mengeluarkan permintaan pos kecil:

<a href="https://www.php.cn/link/fef56cae0dfbabedeadb64bf881ab64f" ping="http://localhost:3000/log">
  Pergi ke halaman lain
</a>
Salin selepas log masuk

Tajuk permintaan ini akan mengandungi halaman di mana pautan diklik (ping-dari), dan nilai HREF pautan (ping-to):

 <code>headers: { 'ping-from': 'http://localhost:3000/', 'ping-to': 'https://www.php.cn/link/fef56cae0dfbabedeadb64bf881ab64f' 'content-type': 'text/ping' // ...其他标头},</code>
Salin selepas log masuk

Ia secara teknikal sama dengan menghantar suar, tetapi mempunyai beberapa batasan yang ketara:

  1. Ia adalah terhad untuk digunakan untuk pautan, yang akan menjadi pilihan yang buruk jika anda perlu menjejaki data yang berkaitan dengan interaksi lain seperti klik butang atau borang penyerahan.
  2. Pelayar menyokong dengan baik, tetapi tidak hebat. Pada masa penulisan, Firefox secara khusus tidak membolehkannya secara lalai.
  3. Anda tidak boleh menghantar data tersuai dengan permintaan. Seperti yang dinyatakan sebelum ini, anda hanya boleh mendapatkan beberapa tajuk ping-* paling banyak, dan mana-mana tajuk lain.

Semua dalam semua, ping adalah alat yang hebat jika anda hanya menghantar permintaan mudah dan tidak mahu menulis mana -mana JavaScript tersuai. Walau bagaimanapun, jika anda perlu menghantar lebih banyak kandungan, ia mungkin bukan pilihan terbaik.

Jadi, mana yang harus saya pilih?

Sudah tentu ada perdagangan ketika menghantar permintaan terakhir kedua menggunakan fetch() atau sendBeacon() dengan keepalive . Untuk membantu memberitahu pendekatan mana yang terbaik untuk situasi yang berbeza, berikut adalah beberapa perkara yang perlu dipertimbangkan:

Anda mungkin memilih mengambil () KeepAlive dalam kes -kes berikut:

  • Anda perlu lulus tajuk tersuai dengan mudah menggunakan permintaan.
  • Anda ingin mengeluarkan permintaan mendapatkan perkhidmatan, bukan permintaan pos.
  • Anda menyokong penyemak imbas yang lebih tua (seperti IE) dan telah mengambil polyfill yang dimuatkan.

Walau bagaimanapun, SendBeacon () mungkin menjadi pilihan yang lebih baik dalam kes -kes berikut:

  • Anda membuat permintaan perkhidmatan mudah yang tidak memerlukan banyak penyesuaian.
  • Anda lebih suka API yang lebih ringkas dan elegan.
  • Anda ingin memastikan bahawa permintaan anda tidak bersaing dengan permintaan keutamaan yang lain yang dihantar dalam permohonan.

Elakkan mengulangi kesilapan yang sama

Terdapat sebab mengapa saya memilih untuk menggali jauh ke dalam cara penyemak imbas mengendalikan permintaan dalam proses apabila halaman berakhir. Tidak lama dahulu, selepas kami memulakan permintaan menembak dengan segera apabila kami menyerahkan borang itu, pasukan kami mendapati bahawa kekerapan jenis log analisis tertentu tiba -tiba berubah. Perubahan ini tiba -tiba dan signifikan - kira -kira 30% daripada apa yang kita lihat dalam sejarah.

Menggali punca masalah ini dan alat yang ada untuk mengelakkan daripada muncul semula masalah yang disimpan pada hari itu. Jadi jika ada, saya berharap dapat memahami nuansa cabaran -cabaran ini dapat membantu seseorang mengelakkan kesakitan yang kita hadapi. Rekod gembira!

Atas ialah kandungan terperinci Dikatakan dengan pasti menghantar permintaan HTTP sebagai pengguna meninggalkan halaman. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan