ASP经典应用中的Multipart/form-data和UTF-8

6

我有一个问题,我真的不明白。我正在尝试在ASP经典应用程序中上传文件,而不使用外部组件。我还想发布一些将存储在数据库中的文本。

文件上传完美,我正在使用这段代码:Upload Files Without COM v3 by Lewis E. Moten III

问题在于其他表单输入字段。我正在使用UTF-8,但它们没有以UTF-8结束。即瑞典字符å ä和ö显示为问号,如果我使用Response.Write打印它们。

我已将文件保存为UTF-8(带BOM),我已添加了meta标签以告知页面它处于UTF-8中。我已设置Response.CharSet =“UTF-8”。

将二进制转换为字符串的函数如下(这是可能出错的唯一地方,因为评论说它提取ANSI字符,但我认为它应该提取Unicode字符):。

Private Function CStrU(ByRef pstrANSI)

    ' Converts an ANSI string to Unicode
    ' Best used for small strings

    Dim llngLength ' Length of ANSI string
    Dim llngIndex ' Current position

    ' determine length
    llngLength = LenB(pstrANSI)

    ' Loop through each character
    For llngIndex = 1 To llngLength

        ' Pull out ANSI character
        ' Get Ascii value of ANSI character
        ' Get Unicode Character from Ascii
        ' Append character to results
        CStrU = CStrU & Chr(AscB(MidB(pstrANSI, llngIndex, 1)))

    Next

End Function

我已创建一个测试asp页面(multiparttest.asp)来复制此操作,需要使用Lewis E.Moten的上传文件才能使其正常工作(我已将他的文件添加到名为upload的子目录中)。
<%Response.CharSet = "UTF-8" %>
<!--#INCLUDE FILE="upload/clsUpload.asp"-->
<html>
    <head>
        <title>Test</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    </head>
    <body>
        <%
        Set objUpload = New clsUpload
        Response.Write( objUpload.Fields("testInput").Value )
        %>
        <form method="post" enctype="multipart/form-data" action="multiparttest.asp">
            <input type="text" name="testInput" />
            <input type="submit" value="submit" />
        </form>

    </body>
</html>

我使用Firefox中的LiveHTTP Headers捕获了请求,并将其保存为UTF-8文件,瑞典字符看起来应该是正确的(它们在LiveHTTP header GUI中不正确,但我猜测GUI本身没有使用正确的编码)。这是POST请求的样子:

http://localhost/testsite/multiparttest.asp

POST /testsite/multiparttest.asp HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://localhost/testsite/multiparttest.asp
Cookie: ASPSESSIONIDASBBRBTT=GLDJDBJALAMJFBFBDCCIONHF; ASPSESSIONIDAQABQBTT=DIPHILKAIICKJOIAIMILAMGE; ASPSESSIONIDCSABTCQS=KMHBLBLABKHCBGPNLMCIPPNJ
Content-Type: multipart/form-data; boundary=---------------------------7391102023625
Content-Length: 150
-----------------------------7391102023625
Content-Disposition: form-data; name="testInput"

åäö
-----------------------------7391102023625--

HTTP/1.x 200 OK
Cache-Control: private
Content-Length: 548
Content-Type: text/html; Charset=UTF-8
Server: Microsoft-IIS/7.0
X-Powered-By: ASP.NET
Date: Tue, 10 Nov 2009 14:20:17 GMT
----------------------------------------------------------

非常感谢您的帮助!

10/11编辑:

我尝试将所有这些内容添加到ASP文件的顶部,由于在其他地方找到的不同建议,在此问题上没有任何不同的结果。

<%@Language=VBScript codepage=65001 %>
<%Response.ContentType="text/html"%>
<%Response.Charset="UTF-8"%>
<%Session.CodePage=65001%>

编辑11/11:

这个问题似乎与UTF-8文本在以multipart/form-data方式提交表单时出现乱码有关。但是他们没有使用ASP或IIS。在IIS中是否可以设置某种字符编码来处理multipart/form-data?我正在使用IIS7。也许我的请求确实存在错误的编码吗?(我现在真的迷失在字符编码世界中)

3个回答

7
您对 CStrU 的分析是正确的。它假设客户端发送的是单字节 ANSI 字符,并且假设客户端和 VBScript 运行所在的区域设置使用的代码页相同。
但是,当使用 UTF-8 时,CStrU 做出的假设将始终是不正确的。据我所知,并没有一个区域设置将 65001 作为其代码页(我认为有一两个使用 65000,但这又是另外一回事)。
下面是一个替代函数,它假设文本使用的是 UTF-8 编码:
 Private Function CStrU(ByRef pstrANSI)

  Dim llngLength '' # Length of ANSI string
  Dim llngIndex '' # Current position
  Dim bytVal
  Dim intChar

  '' # determine length
  llngLength = LenB(pstrANSI)

  '' # Loop through each character
  llngIndex = 1
  Do While llngIndex <= llngLength

   bytVal = AscB(MidB(pstrANSI, llngIndex, 1))
   llngIndex = llngIndex + 1

   If bytVal < &h80 Then
    intChar = bytVal
   ElseIf bytVal < &hE0 Then

    intChar = (bytVal And &h1F) * &h40

    bytVal =  AscB(MidB(pstrANSI, llngIndex, 1))
    llngIndex = llngIndex + 1

    intChar = intChar + (bytVal And &h3f)

   ElseIf bytVal < &hF0 Then

    intChar = (bytVal And &hF) * &h1000

    bytVal =  AscB(MidB(pstrANSI, llngIndex, 1))
    llngIndex = llngIndex + 1

    intChar = intChar + (bytVal And &h3F) * &h40

    bytVal =  AscB(MidB(pstrANSI, llngIndex, 1))
    llngIndex = llngIndex + 1

    intChar = intChar + (bytVal And &h3F)

   Else
    intChar = &hBF
   End If

   CStrU = CStrU & ChrW(intChar)
  Loop

 End Function

请注意,由于CStrU已经修正为UTF-8,您的示例页面输出现在看起来是错误的。将文件的代码页设置为65001也是必须的建议。由于您将发送到客户端的字符集设置为“UTF-8”,因此您还需要告诉ASP在使用Response.Write编写文本时使用UTF-8代码页。

1
这是其中一种情况,古老的答案仍对遗留项目有用。 - Dejan Dular

1

我不知道这是否有帮助,但我曾经使用过一些经典 ASP代码来使用 SWFUpload 实用程序(Flash 插件,允许批量上传多个文件)。

ASP 示例代码包括一些全面的代码,解决了字节/Unicode 解码问题,并且类似于您提到的 chr(AscB(MidB(... - 也许看到第二个示例可以帮助您解决问题。


它们似乎使用相同的函数,outPut = outPut & Chr(AscB(MidB(binString, i, 1)))。 奇怪,也许我做错了其他事情。 - fredrik

1
“回到过去”,我曾经使用ASPUpload。它比花时间与表单数据斗争更便宜。有点像ASP.NET,它使常规字段和上传的文件都可用于查询,但它确实(如果我没记错)破坏了表单对象——也就是说,一旦你从ASPUpload中读取,输入流将被消耗,并且尝试使用常规表单输入将失败。
您可以在同一个应用程序中使用这两种方法,但不能在同一个页面请求中同时使用两种方法;基本上选择其中一种(通常基于传入的MIME类型)。

我们曾经使用过ASPUpload,但是因为我们总是忘记在客户的安装中安装该组件,所以我们放弃了它。 - fredrik
@Marc:上传文件时,旧的表单输入本来就会出问题。ASP表单对象不知道如何处理多部分主体,因此即使您自己没有使用输入流,表单对象仍将无用。 - AnthonyWJones
很久以前的事了 - 也许我的意思是如果你尝试先读取ASP Form,那么ASPUpload会不高兴?无论如何:不要在同一个请求中尝试两者;-p - Marc Gravell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接