Pengendalian ralat CFML: cftry, cfcatch, cfthrow dan cfrethrow
Panduan lengkap pengendalian ralat CFML: cftry, cfcatch, cfthrow dan cfrethrow. Belajar jenis ralat, medan objek ralat dan corak log dalam Lucee.

Kandungan
- Pengendalian ralat CFML: cftry, cfcatch, cfthrow dan cfrethrow
- Dua jenis ralat: kompilasi dan runtime
- Struktur asas: cftry, cfcatch dan cffinally
- Jenis cfcatch
- Medan dalam objek ralat
- Membaling ralat sendiri: cfthrow
- Membaling semula: cfrethrow
- Ralat tersuai peringkat aplikasi: onError dan cferror
- Corak log dan pemulihan
- Kesilapan biasa
- Soalan Lazim (FAQ)
- Sumber
- Senarai semak
Pengendalian ralat CFML: cftry, cfcatch, cfthrow dan cfrethrow
Setiap aplikasi yang berjalan lama akan menghadapi ralat, dan kualiti aplikasi CFML banyak ditentukan oleh cara ia menangani ralat itu. CFML menyediakan dua bentuk yang setara: tag cftry, cfcatch, cffinally dan blok try, catch, finally dalam cfscript. Artikel ini membimbing anda daripada membezakan ralat kompilasi dan ralat runtime, kepada membaca medan objek ralat, membaling ralat sendiri dengan cfthrow, membaling semula dengan cfrethrow, dan menangkap ralat di peringkat aplikasi melalui onError dalam Application.cfc. Semua contoh kod di bawah telah dijalankan dalam Lucee 7.1 dan lulus.
Dua jenis ralat: kompilasi dan runtime
Sebelum memilih cara menangkap, anda perlu tahu dua kategori ralat yang berbeza kelakuannya.
Ralat kompilasi berlaku sebelum kod sempat berjalan. Ia ialah ralat sintaks, tag yang tidak dikenali, atau tagar yang tidak sepadan. Enjin membaca templat, gagal menyusunnya, dan terus memulangkan ralat. Ralat jenis ini tidak boleh ditangkap dengan cftry kerana kod itu sendiri tidak pernah mula dilaksanakan. Satu-satunya jalan ialah membetulkan kodnya. Ini sebab utama artikel diagnostik seperti panduan ralat HTTP 500 menekankan pembacaan mesej kompilasi dengan teliti.
Ralat runtime berlaku semasa kod sedang berjalan. Contohnya pemboleh ubah yang tidak wujud, bahagi dengan sifar, datasource yang hilang, atau fail yang tidak ditemui. Ralat jenis ini boleh ditangkap, dicatat, dan dipulihkan. Inilah yang ditangani oleh cftry dan cfcatch.
Perbezaan ini penting kerana ia menentukan jangkaan anda: jika blok cftry anda tidak menangkap apa-apa, semak dahulu sama ada ralat itu sebenarnya ralat kompilasi yang berlaku sebelum blok itu sempat berjalan.
Struktur asas: cftry, cfcatch dan cffinally
Bentuk tag ialah bentuk tertua dan paling biasa dilihat dalam projek lama. Kod berisiko diletakkan dalam cftry, penanganan dalam cfcatch, dan pembersihan dalam cffinally:
<cftry>
<cfset fungsiTidakWujud()>
<cfcatch>
<cfoutput>Ralat: #cfcatch.message#</cfoutput>
</cfcatch>
<cffinally>
<cfoutput> | Pembersihan dijalankan</cfoutput>
</cffinally>
</cftry>
Bentuk skrip ialah bentuk moden dan lebih ringkas, dan disyorkan untuk kod baharu:
<cfscript>
try {
throw( type = "custom", message = "Pengesahan gagal", detail = "Emel tidak sah" );
} catch ( any e ) {
writeOutput( "Jenis: " & e.type & " | " & e.message & " | " & e.detail );
} finally {
writeOutput( " | Bersihkan sumber" );
}
</cfscript>
finally dijalankan tanpa mengira sama ada ralat berlaku atau tidak, jadi ia tempat yang betul untuk menutup sambungan, memadam fail sementara, atau melepaskan sumber lain. Satu perkara penting: kod dalam try yang melemparkan ralat berhenti serta-merta, jadi sebarang baris selepas titik ralat tidak akan dijalankan.
Jenis cfcatch
Atribut type pada cfcatch membolehkan anda menangkap kategori ralat yang berbeza dengan penanganan yang berbeza. Ini lebih baik daripada menangkap semua ralat dengan satu blok, kerana ralat pangkalan data memerlukan tindakan yang berbeza daripada ralat logik.
| Jenis cfcatch | Apa yang ditangkap | Contoh ralat |
|---|---|---|
| any | Semua ralat tanpa mengira jenis | Tangkapan lalai untuk satu blok penanganan umum |
| database | Ralat pangkalan data dan SQL | Datasource tidak wujud, sintaks SQL salah |
| expression | Ralat penilaian ungkapan | Pemboleh ubah tidak wujud, bahagi dengan sifar, indeks tatasusunan di luar julat |
| template | Ralat templat dan halaman | Include yang hilang, yang enjin laporkan sebagai missinginclude |
| custom | Ralat yang dibaling dengan type="custom" | cfthrow type="custom" |
| application | Ralat peringkat aplikasi, juga lalai cfthrow tanpa type | cfthrow message="..." tanpa atribut type |
Satu perkara yang kami sahkan dalam Lucee 7.1: cfthrow tanpa atribut type melemparkan ralat berjenis application, dan cfthrow type="kita.custom.jenis" menyimpan rentetan jenis itu sepenuhnya. cfcatch type="custom" hanya menangkap ralat dengan jenis custom secara literal, jadi ralat tersuai dengan nama lain jatuh kepada blok any.
Medan dalam objek ralat
Apabila ralat ditangkap, objek cfcatch membawa maklumat penuh tentang ralat itu. Dalam skrip ia diakses melalui pemboleh ubah e, dan dalam tag melalui skop cfcatch.
| Medan | Kandungan | Kegunaan biasa |
|---|---|---|
| message | Ringkasan ralat | Dipaparkan kepada pembangun dan ditulis ke log |
| detail | Perincian tambahan | Contohnya senarai nama datasource yang tersedia |
| type | Kategori ralat, contohnya database atau expression | Memilih blok cfcatch yang betul |
| stacktrace | Jejak Java penuh | Menjejak punca sebenar, disimpan dalam log sahaja |
| tagcontext | Tatasusunan struktur yang menunjukkan templat dan baris | Mengetahui fail dan baris yang gagal |
Akses kepada medan ini tidak peka huruf besar kecil, jadi e.message, e.Message dan e.MESSAGE semuanya sama. Kami juga mengesahkan bahawa e.tagContext ialah tatasusunan, bukan rentetan, jadi anda boleh membaca e.tagContext[1] untuk mendapatkan struktur yang mengandungi baris dan templat. Untuk ralat pangkalan data, e.detail mengandungi senarai nama datasource yang tersedia, maklumat yang sama yang anda baca pada halaman ralat penuh.
Membaling ralat sendiri: cfthrow
Tidak semua ralat datang daripada enjin. Apabila logik aplikasi anda menemui keadaan yang tidak sah, anda baling sendiri:
<cftry>
<cfthrow type="validasi" message="Emel sudah didaftarkan">
<cfcatch>
<cfoutput>Jenis ralat: #cfcatch.type# | #cfcatch.message#</cfoutput>
</cfcatch>
</cftry>
Gunakan cfthrow apabila input gagal pengesahan, apabila rekod yang diperlukan tidak ditemui, atau apabila prasyarat perniagaan tidak dipenuhi. Memberi type yang bermakna, seperti validasi atau autentikasi, membolehkan lapisan yang lebih tinggi menangani setiap kes secara berbeza. Dalam skrip, fungsi throw() adalah setara dan menerima argumen type, message dan detail.
Membaling semula: cfrethrow
Ada situasi di mana anda mahu mencatat ralat tetapi tidak mahu menelannya. cfrethrow melemparkan semula ralat yang sama kepada lapisan luar selepas anda sempat mencatatnya:
<cftry>
<cftry>
<cfthrow type="database" message="Sambungan terputus">
<cfcatch>
<cflog text="Ralat sambungan: #cfcatch.message#" type="error">
<cfrethrow>
</cfcatch>
</cftry>
<cfcatch>
<cfoutput>Ditangkap di lapisan luar: #cfcatch.message#</cfoutput>
</cfcatch>
</cftry>
Corak ini berguna dalam lapisan yang mengetahui konteks setempat tetapi tidak berhak memutuskan tindakan akhir. Lapisan dalam mencatat butiran, lapisan luar memutuskan sama ada untuk memaparkan mesej mesra, mencuba semula, atau menggagalkan permintaan.
Ralat tersuai peringkat aplikasi: onError dan cferror
Untuk ralat yang tidak ditangkap di mana-mana, Application.cfc menyediakan kaedah onError. Kaedah ini menerima dua argumen: struct exception dan rentetan eventName, lalu menjadi tempat terakhir untuk mencatat dan memaparkan mesej yang selamat. Bentuknya sama seperti badan blok catch yang sudah anda lihat, tetapi ia dipasang sekali untuk seluruh aplikasi:
<cfscript>
try {
queryExecute( "SELECT * FROM jadual_tidak_wujud", [], { datasource: "luceemy" } );
} catch ( any e ) {
writeLog( text = "Ralat pertanyaan: " & e.message, type = "error", log = "aplikasi" );
writeOutput( "Maaf, berlaku ralat. Sila cuba sebentar lagi." );
}
</cfscript>
Dalam onError sebenar, gantikan writeOutput dengan pemaparan halaman ralat mesra, dan pastikan butiran penuh hanya masuk ke log, bukan ke skrin pelawat. Cara menyediakan Application.cfc dibincangkan dalam panduan memahami Application.cfc.
cferror ialah pendekatan lama yang masih berfungsi: cferror type="exception" template="ralat.cfm" mengarahkan enjin memaparkan templat tertentu apabila ralat jenis itu berlaku. Ia kurang fleksibel berbanding onError kerana ia memisahkan penanganan ke dalam fail lain dan sukar dibawa bersama logik aplikasi, jadi untuk projek baharu onError ialah pilihan yang lebih baik.
Corak log dan pemulihan
Ralat yang ditangkap tidak berguna jika ia hilang tanpa jejak. Tiga corak yang kami syorkan digabungkan bersama.
Pertama, catat setiap ralat ke log dengan writeLog atau tag cflog. Gunakan aras error untuk kegagalan sebenar dan info untuk peristiwa biasa, dan gunakan atribut log untuk memilih log bernama. Corak ini dijelaskan dengan lebih mendalam dalam panduan log dan pemantauan CFML.
Kedua, pulihkan dengan cara yang sesuai dengan jenis ralat. Ralat pangkalan data sementara boleh dicuba semula selepas sedikit masa, ralat pengesahan input boleh memulangkan mesej khusus medan, dan kegagalan yang tidak boleh dipulihkan boleh menggagalkan permintaan dengan bersih.
Ketiga, jangan biarkan halaman ralat lalai mendedahkan butiran dalaman. Halaman ralat Lucee penuh memaparkan laluan fail, nama datasource dan nombor baris, dan ia kelihatan kepada semua pelawat dalam persediaan lalai. Gantikan dengan halaman mesra melalui onError, dan matikan showdebugoutput.
Kesilapan biasa
Kesilapan pertama ialah menelan ralat tanpa log. Blok catch yang kosong menyembunyikan kegagalan sepenuhnya, jadi aplikasi kelihatan berjalan sedangkan data tidak diproses. Sekurang-kurangnya tulis e.message ke log.
Kesilapan kedua ialah menangkap terlalu luas. Membungkus setiap blok kod dengan catch ( any e ) dan terus memulangkan mesej generik menyukarkan penyahpepijatan, kerana jenis ralat yang berbeza semuanya dilayan sama. Gunakan type untuk memisahkan kategori dan hanya gunakan any sebagai tangkapan terakhir.
Kesilapan ketiga ialah mendedahkan stacktrace kepada pelawat. Jejak Java penuh ialah maklumat berharga untuk penyerang, kerana ia mendedahkan struktur dalaman aplikasi anda. Paparkan mesej ringkas kepada pelawat dan simpan stacktrace hanya dalam log. Untuk menyahpepijat secara interaktif tanpa mendedahkan apa-apa kepada pengguna, gunakan penyahpepijat VS Code.
Soalan Lazim (FAQ)
Apakah beza ralat kompilasi dan ralat runtime dalam CFML?
Ralat kompilasi berlaku sebelum kod dijalankan, contohnya sintaks salah atau tag tidak dikenali, dan tidak boleh ditangkap dengan cftry. Ralat runtime berlaku semasa kod berjalan dan boleh ditangkap dengan cftry dan cfcatch.
Bagaimana cara menulis try catch dalam cfscript?
Gunakan blok try, catch ( any e ) dan finally dalam cfscript, kemudian akses medan ralat melalui pemboleh ubah e seperti e.message, e.detail dan e.type.
Apakah jenis ralat yang boleh ditangkap cfcatch?
Antaranya any, database, expression, template, custom dan application. Setiap jenis membolehkan anda menangani kategori ralat yang berbeza dengan tindakan yang berbeza.
Apakah medan penting dalam objek ralat?
message untuk ringkasan, detail untuk perincian tambahan, type untuk kategori, stacktrace untuk jejak Java, dan tagcontext untuk lokasi templat dan baris.
Bila saya perlu guna cfrethrow?
Guna cfrethrow apabila anda mahu mencatat ralat pada satu lapisan tetapi membiarkan lapisan yang lebih tinggi memutuskan tindakan akhir, contohnya mencatat di lapisan data dan memaparkan mesej mesra di lapisan pengawal.
Sumber
- cftry, docs.lucee.org
- cfcatch, docs.lucee.org
- cfthrow, docs.lucee.org
- cfrethrow, docs.lucee.org
- cferror, docs.lucee.org
- writeLog(), docs.lucee.org
Senarai semak
Untuk menutup, ini senarai semak yang boleh anda jalankan pada setiap aplikasi CFML. Balut kod berisiko dengan cftry dan cfcatch, gunakan type yang khusus dan bukan any untuk setiap kategori, catat setiap ralat ke log dengan writeLog atau cflog, pulihkan dengan cara yang sesuai dengan jenis ralat, baling ralat sendiri dengan cfthrow apabila logik perniagaan gagal, gunakan cfrethrow apabila lapisan dalam hanya mencatat, pasang onError dalam Application.cfc untuk ralat yang tidak ditangkap, dan pastikan stacktrace hanya masuk ke log dan tidak pernah ke skrin pelawat.