Ralat & Penyelesaian Pasukan Lucee MY

Ralat runtime CFML: skop, kunci hilang dan fungsi yang tiada

Ralat runtime CFML yang mengelirukan: key [X] doesn't exist, local. dalam templat, fileLen tiada, sessionRotate, dan serializeJSON yang menukar kunci.

0
Kandungan

Ralat runtime CFML: skop, kunci hilang dan fungsi yang tiada

Ralat runtime berlaku selepas halaman berjaya disusun. Kod itu sah, tetapi nilainya tidak seperti yang disangka. Lima mesej di bawah ini ialah yang paling kerap mengelirukan kerana mesejnya menyalahkan tempat yang salah.

Kenapa Lucee kata key [JENIS] doesn't exist walaupun medan ada?

Mesej:

key [JENIS] doesn't exist

Ia muncul apabila anda membaca kunci struct atau skop yang tidak ada, dan aplikasi anda berjalan dengan this.nullSupport = false.

Kes yang paling menipu ialah null coalescing pada skop URL.

<cfset jenis = url.jenis ?: "url">

Dalam kebanyakan tetapan, ?: melindungi kunci yang hilang. Tetapi apabila nullSupport dimatikan, Lucee menilai url.jenis dahulu dan membaling ralat sebelum ?: sempat berfungsi. Jadi pertahanan yang anda sangka ada, tiada.

Pembetulan: periksa kunci secara eksplisit.

<cfset jenis = structKeyExists(url, "jenis") ? url.jenis : "url">

Kalau corak ini berulang, bina satu pembantu kecil.

<cfscript>
function p(string nama, string lalai = "") {
    if (structKeyExists(url, arguments.nama) && isSimpleValue(url[arguments.nama])) {
        return url[arguments.nama];
    }
    return arguments.lalai;
}
</cfscript>

Perangkap kedua: ternari yang memakai semula nilai mentah.

<cfset jenis = listFindNoCase("url,teks,wifi", url.jenis) ? url.jenis : "url">

Walaupun pemeriksaan listFindNoCase selamat, cabang ? masih membaca url.jenis dan boleh membaling. Guna nilai yang sudah dibaca melalui pembantu itu.

Kenapa local. tidak wujud dalam templat CFM?

Mesej:

variable [local] doesn't exist

Skop local. hanya sah di dalam fungsi dan method komponen. Dalam templat .cfm di peringkat atas, tiada skop lokal, jadi setiap local.x gagal.

<cfset local.harga = 12.50>

Pembetulan dalam templat: guna nama biasa atau variables..

<cfset harga = 12.50>
<cfset variables.harga = 12.50>

Peraturan yang sama terpakai pada var di peringkat templat. var i = 0 dalam .cfm membalas Unsupported Context for Local Scope, dan for (var i = 1; i <= 3; i++) juga gagal walaupun ia kelihatan seperti gelung biasa. Di dalam fungsi, kedua-duanya wajib.

Kenapa fileLen tiada dalam Lucee 7?

Mesej:

No matching function [FILELEN] found

fileLen() ialah fungsi yang biasa dalam ColdFusion, tetapi ia tiada dalam Lucee 7.1. Ini jenis ralat yang mengelirukan kerana editor mungkin menyiapkannya secara automatik, jadi anda menyangka ia wujud.

Pembetulan: baca saiz melalui getFileInfo().

<cfset saiz = getFileInfo(expandPath("./laporan.csv")).size>

Kaedah yang sama memberi lastModified, type dan name. Untuk menyemak sama ada sesuatu fungsi wujud sebelum menggunakannya, tanya enjin.

<cfset ada = structKeyExists(getFunctionList(), "fileLen")>

Jawapannya false pada Lucee 7.1, dan true untuk getFileInfo.

Kenapa sessionRotate tidak dijumpai tetapi boleh dipanggil?

Ini keliru kerana dua pemeriksaan memberi jawapan berbeza.

<cfoutput>#isDefined("sessionRotate")#</cfoutput>

Ia mencetak false. Tetapi panggilan di dalam cftry berjaya.

<cftry>
    <cfset sessionRotate()>
    <cfset berjaya = true>
<cfcatch>
    <cfset berjaya = false>
</cfcatch>
</cftry>

Sebabnya: isDefined memeriksa nama pemboleh ubah, bukan kewujudan fungsi. Fungsi terbina tidak didaftarkan sebagai pemboleh ubah dalam skop.

Cara memeriksa fungsi dengan betul ialah getFunctionList(), bukan isDefined. Untuk kod yang perlu berjalan pada beberapa versi Lucee, balut panggilan itu dalam cftry dan simpan bendera, seperti contoh di atas.

Kenapa serializeJSON menukar kunci struct kepada huruf besar?

Dalam Lucee, serializeJSON() mengubah kunci struct menjadi huruf besar pada output.

<cfset data = { ok: true, jumlah: 49 }>
<cfoutput>#serializeJSON(data)#</cfoutput>

Hasilnya:

{"OK":true,"JUMLAH":49}

Klien JavaScript yang membaca data.ok akan menerima undefined, dan ia kelihatan seperti masalah rangkaian sedangkan ia masalah nama kunci.

Pembetulan di sisi pelayan: beri kunci huruf kecil dalam kontrak API, dan dokumentasikan bahawa Lucee menukarnya. Di sisi klien, baca tanpa mengira huruf besar.

const ok = data.ok ?? data.OK;

Kalau anda mengawal kedua-dua hujung, lebih selamat gunakan nama kunci yang memang huruf besar di pelayan, supaya tiada pemetaan diperlukan.

Corak di sebalik lima ralat ini

Empat daripada lima ralat ini berlaku kerana anda menganggap CFML berkelakuan seperti JavaScript. ?: tidak melindungi kunci pada skop tertentu, local. bukan konsep templat, isDefined bukan pemeriksa fungsi, dan serializeJSON bukan penyalin struktur.

Satu tabiat menyelesaikan sebahagian besarnya: baca nilai sekali ke dalam pemboleh ubah tempatan, semak kewujudannya secara eksplisit, dan jangan bergantung pada operator yang kelihatan seperti JavaScript.

Tabiat kedua ialah menghantar nilai melalui argumen, bukan melalui skop. Apabila fungsi membaca url atau form secara terus, fungsi itu hanya boleh diuji melalui satu laluan, dan kegagalan skop menjadi masalah yang sukar diulang. Apabila nilai dihantar sebagai argumen, ujian boleh memberi nilai yang tepat, dan ralat skop hilang daripada fungsi itu sepenuhnya. Dalam aplikasi yang besar, perbezaan ini menentukan sama ada pepijat boleh dihasilkan semula dalam satu minit atau satu jam.

Ralat yang berlaku sebelum halaman berjalan mempunyai punca yang berbeza, dan ralat yang muncul sebagai halaman 500 tanpa mesej selalunya datang daripada datasource atau kebenaran fail.

Cara mengesan skop yang salah dalam beberapa minit

Apabila satu halaman memberi ralat skop, jangan baca seluruh fail. Tiga langkah ini mengecilkan kawasan carian dengan cepat.

Mula dengan mencetak nilai yang terlibat sebelum baris yang gagal.

<cfdump var="#url#" label="URL">
<cfdump var="#variables#" label="VARIABLES">

cfdump menunjukkan kunci sebenar dan huruf besar sebenar. Dalam kebanyakan kes, kunci yang anda sangka ada tidak pernah sampai ke skop itu, kerana borang tidak menghantarnya atau nama medan berbeza satu huruf.

Kemudian periksa dari mana nilai itu sepatutnya datang. Kalau ia parameter URL, cetak cgi.query_string. Kalau ia borang, cetak form.fieldnames. Kalau ia sesi, cetak structKeyList(session).

Akhir sekali, uji satu baris itu sahaja dalam halaman kosong.

<cfparam name="url.jenis" default="url">
<cfoutput>#url.jenis#</cfoutput>

Kalau halaman kosong berjaya, masalahnya bukan pada skop tetapi pada tempat anda membacanya, contohnya di dalam komponen yang mempunyai skop sendiri. Komponen tidak mewarisi skop templat secara automatik, jadi nilai yang ada dalam .cfm tidak semestinya ada dalam CFC yang dipanggil dari situ. Hantar nilai itu sebagai argumen, dan baca argumen itu secara eksplisit di dalam fungsi. Cara itu juga menjadikan fungsi itu boleh diuji tanpa halaman.

Jadual ringkas untuk lima ralat dalam artikel ini:

MesejPuncaPembetulan
key [X] doesn't exist?: tidak melindungi skopstructKeyExists
variable [local] doesn't existlocal. dalam templatnama biasa atau variables.
No matching function [FILELEN]fungsi tiada dalam Lucee 7getFileInfo().size
isDefined pulang falsememeriksa pemboleh ubah, bukan fungsigetFunctionList()
kunci JSON huruf besarserializeJSON menormalkan kuncibaca tanpa mengira huruf

Soalan Lazim

Kenapa mesej menyebut kunci dalam huruf besar sedangkan saya tulis huruf kecil? Lucee menormalkan nama kunci dalam mesej ralat. Yang penting ialah kunci itu tiada pada masa bacaan, bukan ejaannya.

Boleh saya hidupkan nullSupport supaya ?: berfungsi? Boleh, tetapi ia mengubah tingkah laku seluruh aplikasi, termasuk cara isNull dan perbandingan berfungsi. Untuk satu pembetulan kecil, lebih selamat guna structKeyExists.

Adakah getFileInfo berfungsi pada fail besar? Ya. Ia membaca metadata fail, bukan kandungannya, jadi saiz fail tidak menjejaskan masa.

Kenapa templat saya gagal hanya apabila satu blok tertentu dijalankan? Kerana ralat local. dan var berlaku semasa blok itu disusun, bukan semasa fail dibaca. Blok yang tidak pernah dijalankan tidak pernah menghasilkan ralat.

Bagaimana mengelak ralat jenis ini semasa menulis? Simpan logik dalam fungsi komponen, dan biarkan templat hanya memaparkan nilai. Setiap kali anda menulis local. atau var dalam .cfm, itu tanda logik itu patut berpindah ke CFC.

Sumber

0 komen

0 komen

Log masuk untuk menjawab atau memberi komen.

Log masuk