将阿拉伯文文本发送到 Web 服务

Send Arabic Text to Web Service

好吧,我很困惑。我的问题是我想将 Excel 电子表格的内容以 UTF8 编码发送到 HTTP POST 网络服务 - 即我想支持阿拉伯语文本。

我可以遍历写入流的电子表格的单元格:

Dim fsT 'As New Stream
Set fsT = CreateObject("ADODB.Stream")
fsT.Type = 2'Specify stream type - we want To save text/string data.
fsT.Charset = "utf-8" 'Specify charset For the source text data.
fsT.Open 'Open the stream And write binary data To the object

如果我想将其保存到文件中,我可以,我的阿拉伯文文本已保留。

当我将它发送到我的服务时,我将它作为二进制文件发送,这可能是我的失败。

'Change stream type To binary
 fsT.Position = 0
 fsT.Type = adTypeBinary

其次是

 Set oHttp = CreateObject("MSXML2.XMLHTTP.6.0")
 Call oHttp.Open("POST", pHtml, False)
 oHttp.setRequestHeader "Content-Type", "application/text"
 oHttp.setRequestHeader "User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"
 Call oHttp.send(fsT.Read)

不过,我也尝试过在不更改流类型的情况下以文本形式发送

Call oHttp.send(fsT.ReadText)

在这两种情况下,我的服务器上收到的阿拉伯文文本只是一系列问号 ??? ??? ???等等。如果我查看 sft.ReadText.

的输出,这就是我在 VBA 上得到的结果

所以 - 我可以很好地输出到一个文件,但不会丢失我的文本。

我的 VBA 不太好,我确定有人会告诉我我有多愚蠢,但冒着这种风险,任何人都可以提供帮助 - 我一直在尝试多种排列方式事情,我就是无法收到发送过来的文本。

如果两个站点(服务器和客户端)使用相同的语言(在本例中为 HTTP)并且服务器确实希望 POST 请求正文中的 UTF-8 编码字节,那么它应该可以工作。

当然这是断言。但我会证明的。

所以我有以下简单的 Java 服务器 运行:

import java.net.*;
import java.io.*;

class SimplestServerPOST extends Thread {

 private ServerSocket srvSock = null;
 private Socket sock = null;
 private BufferedInputStream bin = null;
 private DataOutputStream out = null;
 private int contentLength = 0;     
 private int c = 0;     

 SimplestServerPOST(int port, int timeout) {

  super();

  try {
   System.out.println("Server start.");
   srvSock = new ServerSocket(port, 5);
   srvSock.setSoTimeout(timeout);
   start();
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 public void run() {
  System.out.println("Server run.");

  while (true) {
   try {
    sock = srvSock.accept();
//Begin request-handling
    try {
     StringBuffer headerLine = new StringBuffer("");
     bin = new BufferedInputStream(sock.getInputStream());
     out = new DataOutputStream(sock.getOutputStream());

     while ((c = bin.read()) >= 0) {
      if ((c == 10) || (c == 13)) { //if there is a linebreak, then the line ends
       if (c == 13) { //handle CRLF linebreak
        bin.mark(1);
        if (bin.read() != 10) bin.reset();
       }

       if (headerLine.length() == 0) break; //the whole header section ends if the first empty line occurs
       //get the content-length header
       if (headerLine.toString().toLowerCase().startsWith("content-length")) {
        contentLength = Integer.parseInt(headerLine.toString().split(" ")[1]);
       }

       System.out.println(headerLine.toString());

       headerLine.delete(0, headerLine.length()); //new headerline
      } else {
       headerLine.append((char)c); //get one byte for headerline
      }
     }

     byte[] buffer = new byte[contentLength];
     bin.read(buffer);

     System.out.println(new String(buffer, "UTF-8"));

     FileWriter fw = new FileWriter("POSTContent.txt");
     fw.write(new String(buffer, "UTF-8"));
     fw.close();

     out.writeBytes("HTTP/1.1 200 OK\r\n");
     out.writeBytes("Connection: close\r\n");
     out.writeBytes("\r\n");
     out.close();
    } catch(Exception e) {
     e.printStackTrace();
    }
//End request-handling
    sock.close();
   } catch (InterruptedIOException e) {
    try {
     int sSTo = srvSock.getSoTimeout();
     // This is only to understand the functionality.
     //System.out.println("No requests for " + sSTo + "ms.");
    } catch (Exception et) {
     et.printStackTrace();
    }
   } catch (Exception e) {
    e.printStackTrace();
   }
  }
 }

 protected void finalize() {
  if (srvSock != null) {
   try {
    srvSock.close();
   } catch (Exception e) {
    e.printStackTrace();
   }
   srvSock = null;
  }
 }
}

class SimplestServerPOSTMain {
 public static void main(String[] args) {
  SimplestServerPOST srv = new SimplestServerPOST(2000, 1000);
 }
}

然后我从以下 VBA 向此服务器发送 POST 请求:

Sub test()

 Set oADOStream = CreateObject("ADODB.Stream")
 oADOStream.Type = 2
 oADOStream.Charset = "utf-8"
 oADOStream.Open

 oADOStream.WriteText "Test umlauts: äöü", 1
 oADOStream.WriteText "Test euro sign: €", 1
 oADOStream.WriteText "Test arabic: " & ChrW(1587) & "  " & ChrW(1588) & "  " & ChrW(1589) & "  " & ChrW(1590), 1

 oADOStream.Position = 0

 Set oWinHTTP = CreateObject("MSXML2.XMLHTTP.6.0")
 oWinHTTP.Open "POST", "http://192.168.0.10:2000", False

 'oWinHTTP.Send oADOStream.ReadText

 oADOStream.Type = 1
 oWinHTTP.Send oADOStream.Read

End Sub

结果是:

此控制台是 Linux 控制台。 Windows 控制台可能无法正确显示字符。但是文件 POSTContent.txt 应该正确包含它们。

好的 - 感谢您的帮助。我不知道为什么,但是 none 的建议奏效了。但是,我找到了适合我的解决方案。它是:

  1. 创建二进制流,
  2. 将 Excel 中的 Cell 值写入 ByteArray - 并将字节数组写入流
  3. 发送流 - 重要的是 - 与空白字符串连接。

我所做的示例如下:

Dim fsT 'As New Stream
Set fsT = CreateObject("ADODB.Stream")
fsT.Type = adTypeBinary 'Specify stream type - we want To save text/string data.

Dim b() As Byte
For Each cell In ActiveSheet.UsedRange.Cells
  b = cell.Value
  fsT.Write b
Next

fsT.Position = 0
Call oHttp.Open("POST", pHtml, False)
oHttp.setRequestHeader "Content-Type", "application/text;charset=UTF-8"
Call oHttp.send("" & fsT.Read)

请注意最后一行,如果我删除字符串的串联,它不会以阿拉伯语形式到达服务器。

我认为这个问题的另一个答案不起作用的原因可能是我获取文本的方式 (cell.Value) 而不是直接将 UniCode 写入流。

从你的回答我猜到了。

您正在做的是:

您在二进制 ADODB.Stream 中写入纯未编码的 Unicode 字节。然后通过连接 "" & fsT.Read 您将创建一个 Unicode 字符串。正如 https://msdn.microsoft.com/en-us/library/ms763706%28v=vs.85%29.aspx 中提到的: "If the input type is a BSTR, the response is always encoded as UTF-8." 因此 IXMLHTTPRequest 会将此字符串编码为 UTF-8。

具有 .Charset = "utf-8" 的文本 ADODB.Stream 也将在其 .ReadText 中包含一个 Unicode 字符串。但是改成二进制后,它的.Read开头会有一个UTF-8 BOM(EFBBBF)。这个 BOM 是混淆您的 Web 服务的原因。

如果

请试试
 Set fsT = CreateObject("ADODB.Stream")
 fsT.Charset = "UTF-8"
 fsT.Type = 2

 fsT.Open

 For Each cell In ActiveSheet.UsedRange.Cells
  fsT.WriteText cell.Value
 Next

 fsT.Position = 0

 Set oHttp = CreateObject("MSXML2.XMLHTTP.6.0")
 oHttp.Open "POST", pHtml, False
 oHttp.send "" & fsT.ReadText

也可以。如果是这样,那么我认为这是更清洁的解决方案。