SOAP dan WSDL dalam CFML: cfinvoke dan kesilapan biasa
Panduan memanggil perkhidmatan SOAP dari CFML dalam Lucee: createObject webservice, cfinvoke, membaca WSDL, jenis data dan ralat biasa yang diuji sendiri.

Kandungan
- SOAP dan WSDL dalam CFML: cfinvoke dan kesilapan biasa
- Apa itu WSDL dan kenapa ia penting
- Cara terpantas: createObject("webservice")
- cfinvoke: gaya tag untuk panggilan SOAP
- Jenis data dan pertukaran nilai
- Kesilapan biasa dan cara mengelakkannya
- Uji perkhidmatan sebelum integrasi
- Tangkap ralat dengan cftry
- Bila guna SOAP dan bila guna REST
- Soalan Lazim
SOAP dan WSDL dalam CFML: cfinvoke dan kesilapan biasa
SOAP ialah protokol lama yang masih hidup dalam banyak sistem kerajaan dan perusahaan, dan CFML menyokongnya terus tanpa pustaka tambahan selagi sambungan Axis dipasang. Artikel ini menunjukkan cara memanggil perkhidmatan SOAP daripada Lucee CFML dengan createObject("webservice") dan cfinvoke, cara membaca WSDL untuk memahami perkhidmatan itu, dan kesilapan biasa yang membuat panggilan gagal. Setiap contoh diuji pada Lucee 7.1 dengan perkhidmatan SOAP tempatan.
Apa itu WSDL dan kenapa ia penting
WSDL (Web Services Description Language) ialah fail XML yang menghuraikan perkhidmatan SOAP: operasi yang wujud, parameter setiap operasi, jenis datanya, dan alamat titik akhir. Ia ibarat kontrak antara pelanggan dan pelayan. Sebelum menulis satu baris kod, buka WSDL itu dan baca operasinya, kerana hampir semua ralat SOAP berpunca daripada memanggil nama kaedah atau jenis data yang tidak wujud dalam kontrak itu.
Dalam Lucee, satu CFC yang fungsinya ditanda remote boleh dihidangkan sebagai perkhidmatan SOAP secara automatik dengan menambah ?wsdl pada URLnya. Ini CFC contohnya:
component {
remote numeric function tambah(required numeric a, required numeric b) {
return arguments.a + arguments.b;
}
remote string function sapaan(required string nama) {
return "Halo " & arguments.nama;
}
}
Apabila fail ini diakses dengan ?wsdl, Lucee menjana WSDL dengan Apache Axis 1.4, dan anda boleh membukanya terus dalam pelayar. WSDL untuk contoh di atas mendedahkan dua operasi: tambah dengan parameter a dan b berjenis xsd:double, dan sapaan dengan parameter nama berjenis xsd:string. Elemen wsdl:message menamakan setiap operasi beserta parameter input dan outputnya, manakala wsdl:portType menyenaraikan operasi yang tersedia. Perhatikan bahawa jenis dalam WSDL itulah yang menentukan cara nilai ditukar, bukan jenis CFML pada sisi pelanggan.
Cara terpantas: createObject("webservice")
Cara paling ringkas untuk memanggil perkhidmatan ialah mencipta objek webservice dan memanggil kaedahnya terus seperti kaedah CFC biasa:
r = createObject("webservice", "http://127.0.0.1:8888/uji/svc.cfc?wsdl");
hasilTambah = r.tambah(2, 3);
sapaan = r.sapaan("Lucee");
writeOutput("tambah=" & hasilTambah & " | sapaan=" & sapaan);
Blok ini memulangkan tambah=5 | sapaan=Halo Lucee pada rig ujian. Nama kaedah dan bilangan hujah mesti sepadan tepat dengan WSDL, kerana Lucee tidak meneka, ia membina panggilan SOAP berdasarkan kontrak itu. Jangan letak var atau local. pada peringkat templat, ia akan ralat, jadi tulis terus pemboleh ubah biasa seperti dalam contoh.
Mencipta objek webservice melibatkan kerja memuatkan dan menghurai WSDL, jadi untuk kod yang kerap berjalan dalam aplikasi, simpan objek itu dalam skop aplikasi dan guna semula dan bukannya menciptanya semula pada setiap permintaan.
cfinvoke: gaya tag untuk panggilan SOAP
Jika anda lebih suka sintaks tag, cfinvoke melakukan kerja yang sama dan membiarkan anda menamakan pemboleh ubah pulangan dengan jelas:
<cfinvoke webservice="http://127.0.0.1:8888/uji/svc.cfc?wsdl" method="tambah" returnvariable="hasilTambah">
<cfinvokeargument name="a" value="2">
<cfinvokeargument name="b" value="3">
</cfinvoke>
<cfoutput>tambah=#hasilTambah#</cfoutput>
returnvariable menyimpan hasil panggilan dalam pemboleh ubah yang anda namakan, dan setiap <cfinvokeargument> menghantar satu hujah bernama. Ini lebih jelas untuk pembaca yang datang dari latar belakang tag ColdFusion, dan hasilnya sama sahaja. Kedua-dua gaya sah dan boleh dicampur dalam aplikasi yang sama, jadi pilih yang lebih mudah dibaca oleh pasukan anda.
Jenis data dan pertukaran nilai
Kontrak WSDL menentukan jenis, dan Lucee menukar nilai CFML anda mengikut jenis itu. Kerana a dan b diisytihar xsd:double, menghantar nombor bulat, nombor perpuluhan, malah rentetan angka semuanya ditukar kepada angka dengan betul. Contoh berikut memulangkan 5.75, menunjukkan nombor perpuluhan mengalir terus tanpa perlu javacast:
r = createObject("webservice", "http://127.0.0.1:8888/uji/svc.cfc?wsdl");
writeOutput("tambah_perpuluhan=" & r.tambah(2.5, 3.25));
Kelonggaran ini berguna, tetapi ia juga punca ralat senyap: jika WSDL mengisytihar xsd:string dan anda menghantar nombor, atau sebaliknya, hasilnya mungkin ditukar dengan cara yang tidak anda jangka. Sentiasa semak jenis dalam WSDL sebelum menghantar nilai. Jika anda perlu memaksa satu jenis tertentu secara eksplisit, fungsi javacast tersedia, tetapi untuk SOAP ia jarang diperlukan kerana WSDL yang menentukan penukaran itu.
Kesilapan biasa dan cara mengelakkannya
Jadual berikut menyenaraikan kesilapan yang paling kerap berlaku dan pembetulannya:
| Kesilapan | Simptom | Pembetulan |
|---|---|---|
Lupa ?wsdl pada URL | Ralat "tidak dapat memuatkan" atau 404 | Tambah ?wsdl pada penghujung URL |
| Port salah dalam bekas | Sambungan ditolak atau masa tamat | Guna port dalaman bekas, bukan port hos |
| Nama kaedah tidak sepadan WSDL | Ralat kaedah tidak wujud | Baca WSDL dan salin nama kaedah tepat |
var pada peringkat templat | Ralat sintaks semasa kompil | Tulis pemboleh ubah biasa tanpa var |
| Tiada pengendalian ralat | Halaman 500 tanpa mesej berguna | Balut panggilan dalam try dan catch |
Satu kesilapan yang kerap berlaku khusus dalam persekitaran Docker atau rangkaian dalaman ialah port. Perkhidmatan yang sama boleh dicapai melalui port yang berbeza bergantung pada dari mana anda memanggilnya: daripada kod CFML yang berjalan dalam bekas, gunakan port dalaman enjin, manakala daripada curl di mesin hos, gunakan port yang dipetakan. Dua nombor yang berbeza, satu perkhidmatan, dan inilah punca "ia berfungsi dari pelayar tetapi tidak dari kod".
Uji perkhidmatan sebelum integrasi
Sebelum menulis logik perniagaan di atas panggilan SOAP, sahkan dahulu bahawa WSDL boleh dicapai dan memulangkan XML yang sah. Dari mesin hos, ini cukup dengan satu perintah:
curl -s "http://127.0.0.1:8905/uji/svc.cfc?wsdl"
Dari dalam kod CFML, anda boleh memeriksa titik akhir itu dengan cfhttp sebelum mencipta objek webservice:
cfhttp(url="http://127.0.0.1:8888/uji/svc.cfc?wsdl", method="get", result="res");
writeOutput("status=" & res.statusCode & " | saiz=" & len(res.fileContent));
Blok ini memulangkan status=200 | saiz=3035 pada rig ujian, iaitu bukti WSDL wujud dan bukan halaman ralat. Periksa juga kandungan res.fileContent untuk memastikan ia mengandungi tag wsdl:definitions dan bukan halaman HTML ralat. Langkah kecil ini menjimatkan masa yang banyak, kerana ia memisahkan masalah rangkaian daripada masalah integrasi sebelum anda menyentuh satu baris logik perniagaan.
Tangkap ralat dengan cftry
Panggilan SOAP boleh gagal atas banyak sebab: pelayan mati, WSDL berubah, atau rangkaian terputus. Balut panggilan dalam blok try supaya kegagalan tidak menamatkan seluruh halaman dengan 500 kosong:
try {
r = createObject("webservice", "http://127.0.0.1:8888/uji/svc.cfc?wsdl");
writeOutput("tambah=" & r.tambah(2, 3));
} catch (any e) {
writeOutput("RALAT: " & e.message);
}
Ini menukar kegagalan menjadi mesej yang boleh dibaca dan dilog, dan anda boleh mengambil tindakan sandaran dalam blok catch, contohnya memanggil perkhidmatan sandaran atau memulangkan nilai lalai. Untuk pemahaman yang lebih lengkap tentang menangkap dan melog ralat, baca panduan pengendalian ralat cftry.
Bila guna SOAP dan bila guna REST
SOAP masih wujud kerana kontraknya yang tegas, tetapi kebanyakan API moden memilih REST. Jika perkhidmatan yang anda integrasikan menyediakan REST, gunakan cfhttp seperti dalam panduan memanggil API luar atau panduan REST API dalam Lucee. SOAP masuk akal apabila sistem lama atau vendor kerajaan menuntutnya, dan dalam kes itu teknik dalam artikel ini yang anda perlukan. Banyak integrasi Malaysia seperti MyInvois kini berasaskan REST dan JSON, jadi kenali kedua-dua gaya dan pilih mengikut kontrak yang diberikan vendor.
Akhirnya, ingat bahawa Lucee berjalan di atas JVM dan sambungan SOAP ialah pembalut di atas Apache Axis, jadi jika anda perlu memahami apa yang berlaku di bawah, panduan integrasi Java menerangkan sempadan JVM itu.
Soalan Lazim
Adakah SOAP memerlukan sambungan khas dalam Lucee?
Ya, sambungan Axis mesti dipasang untuk createObject("webservice") dan cfinvoke berfungsi. Dalam kebanyakan pemasangan ia sudah ada, tetapi jika anda mendapat ralat tentang webservice, semak senarai sambungan dalam pentadbir Lucee dahulu.
Kenapa panggilan saya berfungsi dari pelayar tetapi gagal dari kod CFML?
Kemungkinan besar port. Kod yang berjalan dalam bekas atau rangkaian dalaman mesti menggunakan port dalaman perkhidmatan, bukan port yang dipetakan ke mesin hos. Semak dari mana kod itu sebenarnya berjalan dan gunakan port yang sesuai.
Bolehkah saya memanggil SOAP dengan cfhttp secara manual?
Boleh, dengan membina sampul SOAP XML dan menghantarnya dengan cfhttp, tetapi ia jauh lebih rumit daripada createObject("webservice") atau cfinvoke, yang membina sampul itu untuk anda. Gunakan cfhttp untuk SOAP hanya apabila anda perlu mengawal XML mentah.
Bagaimana saya tahu operasi apa yang ada dalam WSDL?
Buka URL WSDL dalam pelayar atau dengan curl, dan cari unsur wsdl:operation atau mesej wsdl:message. Nama operasi dan parameter tersenarai di sana, dan itulah nama yang anda salin ke dalam kod.
Adakah saya perlu menutup atau membersihkan objek webservice?
Tidak, objek webservice tidak perlu ditutup seperti sambungan pangkalan data. Ia ialah stub dalam memori, dan Lucee menguruskan hayatnya. Namun, elakkan menciptanya semula dalam gelung, simpan objek itu dan gunakan semula.