Cara meneruskan "Null" (nama asli nyata!) Ke layanan web SOAP di ActionScript 3

4636

Kami memiliki karyawan yang bernama Null. Aplikasi pencarian karyawan kami terbunuh ketika nama belakang itu digunakan sebagai istilah pencarian (yang sekarang sudah cukup sering terjadi). Kesalahan yang diterima (terima kasih Fiddler!) Adalah:

<soapenv:Fault>
   <faultcode>soapenv:Server.userException</faultcode>
   <faultstring>coldfusion.xml.rpc.CFCInvocationException: [coldfusion.runtime.MissingArgumentException : The SEARCHSTRING parameter to the getFacultyNames function is required but was not passed in.]</faultstring>

Lucu ya?

Tipe parameternya adalah string.

Saya menggunakan:

  • WSDL ( SABUN )
  • Flex 3.5
  • ActionScript 3
  • ColdFusion 8

Perhatikan bahwa kesalahan tidak terjadi ketika memanggil layanan web sebagai objek dari halaman ColdFusion.

tagihan
sumber
6
Ini mungkin tidak membantu Anda banyak dengan masalah tertentu, tetapi SOAP 1.2 memungkinkan untuk nilai-nilai nullable, lihat w3.org/TR/2001/WD-soap12-20010709/#_Toc478383513
JensG
6
Saya merasa itu melibatkan Dave Null.
George Gibson
2
Setidaknya itu tidak melibatkan Chuck Norris. Inilah alasan untuk menjauh darinya dalam kode: codesqueeze.com/...
SDsolar
42
Apakah karyawan tersebut mempertimbangkan untuk mengubah namanya?
Tatranskymedved
11
Dia harus benar-benar mempertimbangkan untuk membeli anjing Pointer dan memanggilnya NullPointer.
Antonio Alvarez

Jawaban:

1109

Melacaknya

Pada awalnya saya pikir ini adalah bug paksaan di mana nullmenjadi dipaksa "null"dan ujian "null" == nullberlalu. Ini bukan. Saya dekat, tetapi sangat, sangat salah. Maaf soal itu!

Sejak itu saya telah melakukan banyak mengutak - atik wonderfl.net dan menelusuri kode di mx.rpc.xml.*. Pada baris 1795 dari XMLEncoder(dalam sumber 3.5), dalam setValue, semua XMLEncoding bermuara pada

currentChild.appendChild(xmlSpecialCharsFilter(Object(value)));

yang pada dasarnya sama dengan:

currentChild.appendChild("null");

Kode ini, menurut biola asli saya, mengembalikan elemen XML yang kosong. Tapi kenapa?

Sebab

Menurut komentator Justin Mclean pada laporan bug FLEX-33664 , berikut ini adalah pelakunya (lihat dua tes terakhir di biola saya yang memverifikasi ini):

var thisIsNotNull:XML = <root>null</root>;
if(thisIsNotNull == null){
    // always branches here, as (thisIsNotNull == null) strangely returns true
    // despite the fact that thisIsNotNull is a valid instance of type XML
}

Ketika currentChild.appendChilddilewatkan string "null", pertama-tama mengubahnya menjadi elemen XML root dengan teks null, dan kemudian menguji elemen tersebut terhadap nol literal. Ini adalah tes kesetaraan yang lemah, sehingga XML yang berisi null dipaksakan ke tipe nol, atau tipe null dipaksakan ke elemen xml root yang berisi string "null", dan tes yang melewati tempat itu bisa dikatakan gagal. Salah satu perbaikan mungkin untuk selalu menggunakan tes kesetaraan yang ketat ketika memeriksa XML (atau apa pun, benar-benar) untuk "nullness."

Larutan

Satu-satunya solusi yang masuk akal yang dapat saya pikirkan, singkat untuk memperbaiki bug ini di setiap versi ActionScript, adalah dengan menguji bidang untuk "null" dan menghindarinya sebagai nilai CDATA .

Nilai CDATA adalah cara yang paling tepat untuk mengubah seluruh nilai teks yang jika tidak akan menyebabkan masalah penyandian / penguraian. Pengkodean hex, misalnya, dimaksudkan untuk karakter individu. Nilai CDATA lebih disukai ketika Anda melarikan diri dari seluruh teks elemen. Alasan terbesar untuk ini adalah menjaga keterbacaan manusia.

Ben Burns
sumber
298

Pada catatan xkcd , situs web Bobby Tables memiliki saran yang baik untuk menghindari interpretasi data pengguna yang tidak benar (dalam hal ini, string "Null") dalam kueri SQL dalam berbagai bahasa, termasuk ColdFusion .

Tidak jelas dari pertanyaan bahwa ini adalah sumber masalah, dan memberikan solusi yang dicatat dalam komentar pada jawaban pertama (menanamkan parameter dalam struktur) sepertinya ada sesuatu yang lain.

Alex Dupuy
sumber
239

Masalahnya bisa di encoder SOAP Flex. Coba rentangkan encoder SOAP di aplikasi Flex Anda dan debug program untuk melihat bagaimana nilai nol ditangani.

Dugaan saya adalah, ini dilewatkan sebagai NaN (Bukan Angka). Ini akan mengacaukan proses pembatalan pesan SOAP suatu saat (terutama di server JBoss 5 ...). Saya ingat memperluas encoder SOAP dan melakukan pemeriksaan eksplisit tentang bagaimana NaN ditangani.

uncaught_exceptions
sumber
12
name = "Null" ini tentu saja berguna, dan saya tidak melihat bagaimana itu terkait dengan NaN.
eckes
129

@ doc_180 memiliki konsep yang benar, kecuali ia fokus pada angka, sedangkan poster aslinya memiliki masalah dengan string.

Solusinya adalah mengubah mx.rpc.xml.XMLEncoderfile. Ini adalah baris 121:

    if (content != null)
        result += content;

(Saya melihat Flex 4.5.1 SDK; nomor baris mungkin berbeda di versi lain.)

Pada dasarnya, validasi gagal karena 'konten adalah nol' dan karenanya argumen Anda tidak ditambahkan ke Paket SOAP keluar; sehingga menyebabkan kesalahan parameter yang hilang.

Anda harus memperluas kelas ini untuk menghapus validasi. Kemudian ada bola salju besar di rantai, memodifikasi SOAPEncoder untuk menggunakan XMLEncoder Anda yang dimodifikasi, dan kemudian memodifikasi Operasi untuk menggunakan SOAPEncoder Anda yang dimodifikasi, dan kemudian membatalkan WebService untuk menggunakan kelas Operasi alternatif Anda.

Saya menghabiskan beberapa jam untuk itu, tetapi saya harus pindah. Mungkin butuh satu atau dua hari.

Anda mungkin dapat memperbaiki baris XMLEncoder dan melakukan patch monyet untuk menggunakan kelas Anda sendiri.

Saya juga akan menambahkan bahwa jika Anda beralih menggunakan RemoteObject / AMF dengan ColdFusion, null dilewatkan tanpa masalah.


Pembaruan 11/16/2013 :

Saya memiliki satu tambahan lagi untuk komentar terakhir saya tentang RemoteObject / AMF. Jika Anda menggunakan ColdFusion 10; kemudian properti dengan nilai nol pada suatu objek dihapus dari objek sisi server. Jadi, Anda harus memeriksa keberadaan properti sebelum mengaksesnya atau Anda akan mendapatkan kesalahan runtime.

Periksa seperti ini:

<cfif (structKeyExists(arguments.myObject,'propertyName')>
 <!--- no property code --->
<cfelse>
 <!--- handle property  normally --->
</cfif>

Ini adalah perubahan perilaku dari ColdFusion 9; di mana properti nol akan berubah menjadi string kosong.


Edit 12/6/2013

Karena ada pertanyaan tentang bagaimana null diperlakukan, berikut adalah contoh aplikasi cepat untuk menunjukkan bagaimana string "null" akan berhubungan dengan kata null yang disediakan.

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" initialize="application1_initializeHandler(event)">
    <fx:Script>
        <![CDATA[
            import mx.events.FlexEvent;

            protected function application1_initializeHandler(event:FlexEvent):void
            {
                var s :String = "null";
                if(s != null){
                    trace('null string is not equal to null reserved word using the != condition');
                } else {
                    trace('null string is equal to null reserved word using the != condition');
                }

                if(s == null){
                    trace('null string is equal to null reserved word using the == condition');
                } else {
                    trace('null string is not equal to null reserved word using the == condition');
                }

                if(s === null){
                    trace('null string is equal to null reserved word using the === condition');
                } else {
                    trace('null string is not equal to null reserved word using the === condition');
                }
            }
        ]]>
    </fx:Script>
    <fx:Declarations>
        <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>
</s:Application>

Keluaran jejak adalah:

string nol tidak sama dengan kata null reserved menggunakan kondisi! =

string null tidak sama dengan kata null reserved menggunakan kondisi ==

string nol tidak sama dengan kata null reserved menggunakan kondisi ===

JeffryHouser
sumber
8
@ Reboog711 Nama belakang karyawan secara literal adalah string "Null" seperti pada, "Nama saya Pat Null" Jawaban Anda gagal memasukkan nama belakang karyawan. Anda menjawab hanya menyembunyikan fakta bahwa "Null" sedang dipaksa secara tidak tepat ke dalam konsep bahasa nol oleh metode appendChild () seperti yang dijelaskan oleh Ben Burns. Hasilnya masih kegagalan sistem untuk berurusan dengan Tuan atau Ibu Null.
Maxx Daymon
2
@ MaxxDaymon Saya pikir Anda salah mengartikan apa jawaban saya sebenarnya. Itu tidak menghadirkan solusi; melainkan penjelasan mengapa masalah terjadi; dan mengutip kode yang relevan dari Flex Framework. Hasil edit saya yang lebih baru mungkin salah tempat; karena membahas pendekatan alternatif dan tidak terkait langsung dengan pertanyaan awal.
JeffryHouser
1
Anda berada di jalur yang benar, tetapi pada saat itu dalam kode contentadalah string "null", dan "null" == null mengembalikan false, sehingga tes berperilaku seperti yang dimaksudkan. Alih-alih, saya percaya masalahnya adalah campuran bagaimana XML.appendChild menangani argumen string, dan bagaimana elemen XML root yang hanya berisi string "null" dapat dipaksa ke literal null.
Ben Burns
@ Reboog711 Lihatlah biola saya. "null"! = null` kembali trueadalah perilaku yang diinginkan di sini. Jika kebalikannya terjadi, ini akan membuang string "null" dari proses pengkodean, yang sebenarnya akan menjadi penyebab masalah. Namun karena tes ini berhasil, encoder terus berjalan, sampai XML.appendChild membuangnya karena bug paksaan.
Ben Burns
4
Jangan khawatir. Jika Anda ingin melihat masalah sebenarnya, tambahkan var xml:XML = <root>null</root>; var s:String = (xml == null) ? "wtf? xml coerced to null?!!" : "xml not coerced to null."; trace(s);ke sampel kode Anda.
Ben Burns
65

Terjemahkan semua karakter ke dalam persamaan hex-entitas mereka. Dalam hal ini, Nullakan diubah menjadi&#4E;&#75;&#6C;&#6C;

doogle
sumber
41
Tolong jangan lakukan ini. CDATA dibuat untuk digunakan dalam kasus di mana Anda perlu melarikan diri dari seluruh blok teks.
Ben Burns
4
Saya bisa saja salah, tetapi saya tidak berpikir downvoting hanya karena itu bukan solusi Anda adalah bagaimana seharusnya bekerja. Anda juga harus ingat bahwa masalah memerlukan solusi heuristik karena tidak ada satu cara yang jelas, seperti yang dibuktikan oleh beragam solusi yang dipasang. Terakhir, dengan mengingat saya tidak tahu CF, bukankah dekoder hanya menyamakan teks bagian dalam <message><![CDATA[NULL[[> </message> ke teks dalam <message> NULL </ pesan>? Jika demikian, apakah CDATA benar-benar solusi?
doogle
7
Saya downvoted karena ini adalah anti-pola. Bug dalam kasus ini bukan di CF, ada di ActionScript. Namun, Anda tetap mendapatkan poin yang bagus. Saya akan menambahkan tes ke biola saya untuk pengkodean CDATA.
Ben Burns
51

Merangkai nullnilai dalam ActionScript akan memberikan string "NULL". Kecurigaan saya adalah bahwa seseorang telah memutuskan bahwa itu, oleh karena itu, ide yang baik untuk memecahkan kode string "NULL"sebagai null, menyebabkan kerusakan yang Anda lihat di sini - mungkin karena mereka lewat di nullobjek dan mendapatkan string dalam database, ketika mereka tidak ingin itu (jadi pastikan juga untuk memeriksa bug semacam itu).

Andrew Aylett
sumber
Ya, ada sejumlah kemungkinan di sini yang akan membutuhkan lebih banyak debugging untuk dipersempit. 1) Apakah WSDL yang digunakan di sini cukup ekspresif untuk membedakan antara "NULL" sebagai nilai string dan nilai null (atau dihilangkan) yang sebenarnya? 2) Jika demikian, apakah klien menyandikan nama belakang dengan benar (sebagai string dan bukan null literal) 3) Jika demikian, apakah layanan benar menafsirkan "NULL" sebagai string, atau memaksanya dengan nilai nol?
pimlottc
39

Sebagai peretasan, Anda dapat mempertimbangkan untuk memiliki penanganan khusus di sisi klien, mengubah string 'Null' menjadi sesuatu yang tidak akan pernah terjadi, misalnya, XXNULLXX dan mengonversi kembali di server.

Itu tidak cantik, tetapi bisa menyelesaikan masalah untuk kasus batas seperti itu.

Menandai
sumber
32
XXNULLXX bisa menjadi nama juga. Kamu tidak tahu. Mungkin orang di Indonesia tidak memiliki nama keluarga dan menggunakan varian XXX sebagai nama keluarga mereka saat dibutuhkan.
gb.
3
Konsep yang sama, tetapi perbarui semua nama dalam database dan kata pengantar kemudian dengan beberapa karakter (1Null, 1Smith). Lepaskan karakter itu di klien. Tentu saja ini mungkin pekerjaan tungau daripada solusi Reboog.
bobpaul
14
@ BenBurns Ya, tetapi bagaimana jika saya ingin memberi nama anak saya &#78;&#117;&#108;&#108;?
Sirene
@ Sirens Itu bukan masalahnya. Jika nama saya "<& quot;>", maka saya perkirakan nama itu akan lolos dengan benar sebagai & quot; & lt; & amp; quot; & gt; & quot ;, yang tidak perlu dikatakan lagi. Masalah sebenarnya adalah dengan aplikasi berperilaku seolah-olah menggunakan daftar hitam untuk nama.
Tuan Lister
30

Yah, saya kira implementasi Flex dari SOAP Encoder tampaknya membuat serialisasi nilai-nilai nol secara salah. Menerialisasi mereka sebagai String Null sepertinya bukan solusi yang baik. Versi yang benar secara formal tampaknya akan memberikan nilai nol sebagai:

<childtag2 xsi:nil="true" />

Jadi nilai "Null" tidak lebih dari string yang valid, yang persis apa yang Anda cari.

Saya kira memperbaiki ini di Apache Flex seharusnya tidak terlalu sulit untuk dilakukan. Saya akan merekomendasikan membuka masalah Jira atau untuk menghubungi orang-orang dari milis apache-flex. Namun ini hanya akan memperbaiki sisi klien. Saya tidak bisa mengatakan apakah ColdFusion akan dapat bekerja dengan nilai nol yang dikodekan dengan cara ini.

Lihat juga posting blog Radu Cotescu Cara mengirim nilai nol dalam permintaan soapUI .

Christofer Dutz
sumber
6
Ada info bagus di sini, jadi saya tidak akan downvote, tapi saya pikir itu layak untuk dikomentari. Secara default, XMLEncoder.as sebenarnya akan menyandikan nullnilai sebenarnya dengan benar, dengan menetapkan xsi:nil="true"pada elemen. Masalahnya sebenarnya tampak pada cara XMLtipe ActionScript itu sendiri (bukan encoder) menangani string "null".
Ben Burns
22

Ini kludge, tapi dengan asumsi ada panjang minimum untuk SEARCHSTRING, misalnya 2 karakter, substringyang SEARCHSTRINGparameter pada karakter kedua dan lulus sebagai dua parameter sebagai gantinya: SEARCHSTRING1 ("Nu")dan SEARCHSTRING2 ("ll"). Concatenatemereka kembali bersama-sama ketika menjalankan query ke database.

SPitBalls.com
sumber
32
CDATA ditambahkan ke spesifikasi XML untuk menghindari jenis-jenis kludges ini.
Ben Burns
8
Tidak perlu keluar dari "Null" dengan CDATA, tidak ada kata kunci nol dalam XML.
eckes
6
Setuju dengan @eckes. Saya tidak mengerti mengapa ada semua pembicaraan tentang CDATA ini. CDATA hanya berguna untuk keluar dari karakter yang memiliki arti khusus dalam XML. tidak ada: n, u, lmemiliki semantik khusus dalam XML. "NULL" dan "<! [CDATA [NULL]]>" identik dengan parser XML.
jasonkarns
9
@jasonkarns - Saya setuju 100% bahwa seharusnya tidak ada yang istimewa tentang string / teks node NULL, tetapi menjadi bertele-tele, <blah>null</blah>dan <blah><![CDATA[null]]>tidak sama dengan parser XML. Mereka harus menghasilkan hasil yang sama, namun alur logika untuk menangani mereka berbeda. Efek inilah yang kami eksploitasi sebagai solusi untuk bug dalam implementasi XML fleksibel. Saya menganjurkan ini untuk pendekatan lain karena menjaga keterbacaan teks, dan tidak memiliki efek samping untuk parser lainnya.
Ben Burns