用中文字符向Microsoft Translator API发布XML会引发反序列化exception
我正在尝试使用Microsoft Translator API将中文(简体)翻译成英文。
一些要求
-
我必须使用HTTP方法
POST
,而不是使用查询string的GET
,因为我的查询超过了微软的URI限制的15,845个字符(请注意,即使在中文字符的情况下使用less于10,000个字符的限制,是查询string必须进行URL编码,这会显着增加长度,但是在确定字符数之前由Microsoft解码。 -
唯一允许
POST
的翻译HTTP方法是TranslateArrayMethod
,例如TranslateMethod
只允许GET
。 不幸的是,TranslateArrayMethod
只接受一个XML文档,所以我必须使用XML。
以下是我发送的XML文档的示例:
<TranslateArrayRequest> <AppId/> <From>es</From> <Options> <ContentType xmlns="http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2">text/plain</ContentType> </Options> <Texts> <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays"> <![CDATA[Hola]]> </string> </Texts> <To>en</To> </TranslateArrayRequest>
这工作正常,结果是:
<ArrayOfTranslateArrayResponse xmlns="http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <TranslateArrayResponse> <From>es</From> <OriginalTextSentenceLengths xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"> <a:int>4</a:int> </OriginalTextSentenceLengths> <TranslatedText>Hello</TranslatedText> <TranslatedTextSentenceLengths xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"> <a:int>5</a:int> </TranslatedTextSentenceLengths> </TranslateArrayResponse> </ArrayOfTranslateArrayResponse>
但是,如果我添加任何中文字符,如下所示:
<TranslateArrayRequest> <AppId/> <From>zh-CHS</From> <Options> <ContentType xmlns="http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2">text/plain</ContentType> </Options> <Texts> <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays"> <![CDATA[南]]> </string> </Texts> <To>en</To> </TranslateArrayRequest>
我得到一个奇怪的回应:
<html> <body/> <h1>System.Runtime.Serialization.SerializationException</h1> <p>Message: There was an error deserializing the object of type Microsoft.MT.MDistributor.V2.TranslateArrayRequest. Unexpected end of file. Following elements are not closed: TranslateArrayRequest. Line 1, position 298.</p> </html>
请注意,我也尝试不使用CDATA转义,但它没有帮助。 改变From
语言也没有效果。
我正在与Node.js(Javascript),虽然因为这是一个通用的HTTP API,我不认为这应该重要。
好的,我遇到了完全一样的问题,从Node.js调用Microsoft Translator POST API之一。 API工作正常 – 只要没有非ASCII字符,只要返回翻译就可以了,但是当我在POST正文的适当的<string>
部分添加一个重音符号“é”时,它会以一个错误:
<html><body/><h1>System.Runtime.Serialization.SerializationException</h1> <p>Message: There was an error deserializing the object of type Microsoft.MT.MDistributor.V2.TranslateArrayRequest. Unexpected end of file. Following elements are not closed: TranslateArrayRequest. Line 1, position 782.</p> </html>
我发现问题在于Content-Length
头部需要字节长度,但是我一直以字符forms发送长度。 为什么会发生? 那么,测量Node http请求的主体长度的典型方法是调用
var length = body.length
并获得string的“长度”(即字符数)。 当所有的字符都是ASCII时,这是有效的。 但是,事实certificate,在UTF-8中,非ASCII字符(包括我的重音字符“é”)可以多于一个字节。 所以当主体包含非ASCII字符时,字节长度将不再等于字符长度,字符长度不正确。 在这种情况下,它导致Microsoft服务器过早地停止读取消息,生成错误消息。
相反,我们需要用这个调用来测量字节的长度(在Node.js中)
var length = Buffer.byteLength(body, 'utf8')
并在Content-Length
标题中发送该长度,Microsoft Translator API再次运行。
问题最可能的不是中文,而是MS翻译不喜欢新的符号。 当我偶然发现这个错误信息时,我改变了以下内容:
- 在<string>节点的每个内容中用空stringreplace新行字符。 这些字符具有Unicode值:0xA,0xB,0xC,0xD,0x85,0x2028,0x2029
-
在<string>节点的每个内容中用其替代表示replace了XML保留字:
&→&amp;
<→&lt;
>→&gt;
'→'
“→”
- 将整个XML重新排列成单行
之后,一切顺利。 关于你的具体例子,“南”这个符号被翻译为“南”。 我没有使用CDATA转义。