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

时间:2015-05-27 08:51:37

标签: excel vba excel-vba utf-8

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

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

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不是很好,而且我确定我将被告知我有多愚蠢,但冒着风险,任何人都可以提供帮助 - 我一直在尝试许多排列的东西,我只是可以没有收到发送的文字。

3 个答案:

答案 0 :(得分:1)

如果两个站点(服务器和客户端)都使用相同的语言(在本例中为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

结果是:

enter image description here

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

答案 1 :(得分:1)

好的 - 谢谢你的帮助。我不知道为什么,但没有一个建议奏效。然而,我找到了一个适合我的解决方案。它是:

  1. 创建二进制流,
  2. 将单元格值从Excel写入ByteArray - 并将字节数组写入流
  3. 发送信息流 - 重要的是 - 用空白字符串连接。
  4. 我所做的一个例子如下:

    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写入流中的方式。

答案 2 :(得分:1)

从你的答案我怀疑。

您正在做的是以下内容:

您在二进制ADODB.Stream中编写纯未编码的Unicode字节。然后使用连接"" & fsT.Read创建Unicode字符串。与在https://msdn.microsoft.com/en-us/library/ms763706%28v=vs.85%29.aspx中提到的一样:"如果输入类型是BSTR,则响应始终编码为UTF-8。"因此IXMLHTTPRequest会将此字符串编码为UTF-8。

带有ADODB.Stream的文字.Charset = "utf-8"中还会包含一个Unicode字符串.ReadText。但在更改为二进制文件后,它将在其.Read的开头有一个UTF-8 BOM(EFBBBF)。这个BOM令您的网络服务感到困惑。

请尝试

 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

也会奏效。如果是这样,那么在我看来这是更清洁的解决方案。