2015-05-27 45 views
2

好吧,我很困惑。我的问题是,我想用UTF8编码将我的Excel电子表格的内容发送到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不是很好,我敢肯定我会被告知我有多愚蠢,但冒着这个风险,任何人都可以帮忙 - 我一直在尝试很多事物的排列,而我只是无法获得发送的文本。

+0

您可以尝试将“Content-Type”,“application/text”更改为“Content-Type”,“text/html” – Satya

+0

主要问题是Web服务期望从此POST请求得到什么?它真的只是期望在POST正文中的字节数据? Web服务通常如何获取其数据?如果它通常从HTML表单获得,那么它将期望application/x-www-form-urlencoded。 –

+0

我已经尝试过text/html - 同样的问题。 Web服务从InputStream中读取,我的理解是从字节流中读取数据。它不指望HTML表单。对我来说,问题是在VBA方面,如果我去到即时窗口并打印fsT.ReadText的内容,那么这会打印带有问号的文本 - 而不是阿拉伯文本 - 所以我认为这是发送的内容,而是那么它是如何被接收的。 – Agent96

回答

1

从你的答案我得到一个怀疑。

你正在做什么是以下几点:

你写的纯未编码的Unicode二进制字节ADODB.Stream。然后连接"" & 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是混淆你的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 

也会起作用。如果是这样,那么我认为这是更清洁的解决方案。

+0

是的 - 它工作!谢谢你,这是更清洁,并感谢解释实际发生的事情下盖。 – Agent96

+0

这很好。很好知道这一点。提示:如果'ADODB.Stream'只用于创建Unicode字符串对于HTTP-POST,则不需要'.Charset =“UTF-8”',只有当流还应该保存在UTF-8编码文件中时才需要。'ADODB.Stream'的字符集默认为Unicode,这是字符串所需要的。在我看来,它也应该可以与'oHttp.send fsT .ReadText'没有连接,因为'.ReadText'已经返回一个字符串。 –

+0

是的,实际上它没有按照预期的那样工作,没有空字符串连接,也没有utf-8作为字符集。我开始想知道为什么我有这么多问题,并且我认为这是我自己的错,因为我的Java控制台没有被设置为在很多早期测试中输出UTF-8字符。所以我所有的初步试验都给了我虚假的信息。 – Agent96

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文件应该包含它们。

+0

感谢您的建议,这正是我认为它应该工作的原因,这是我原本做的,但无论出于何种原因,我无法得到这个工作,我已经发布了一个答案,为我解决了这个问题 - 我不完全知道它为什么会起作用,但它确实。 – Agent96

0

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

  1. 创建一个二进制流,
  2. 写从Excel单元格值的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到流的方式。