Multipart / form-data и UTF-8 в приложении ASP Classic

У меня есть проблема, которую я действительно не понимаю. Я пытаюсь загрузить файлы в приложение asp classic без использования внешнего компонента. Я также хочу опубликовать текст, который будет храниться в БД. Файл загружается отлично, я использую этот код: Загрузить файлы без COM v3 от Lewis E. Moten III

Проблема заключается в других полях ввода формы. Я использую UTF-8, но они не заканчиваются как UTF-8. Т.е. шведские символы ä ä и ö отображаются в виде вопросительных знаков, если я их распечатаю с помощью Response.Write.

Я сохранил файлы в UTF-8 (с BOM), я добавил метатег, чтобы сообщить странице, что это в 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), чтобы воспроизвести это, для его работы необходим материал для загрузки от Льюиса Э. Мотена (я добавил его файлы в подкаталог под названием 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>

Я захватил запрос, используя LiveHTTP Headers в Firefox, и сохранил его как файл UTF-8, шведские символы выглядят так, как должны (они не выглядели нормально в графическом интерфейсе заголовка LiveHTTP, но я предполагаю, что это графический интерфейс self не использует правильную кодировку). Вот как выглядит запрос 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. Можно ли настроить некую кодировку символов для multipart / form-data в IIS? Я использую IIS7. Может быть, мой запрос все-таки имеет неправильную кодировку? (Я действительно потерян в мире кодирования символов прямо сейчас)

3 ОТВЕТА
РЕШЕНИЕ

Ваш анализ 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. Поскольку вы устанавливаете CharSet, отправляемый клиенту, в «UTF-8», вы должны также указать ASP использовать кодовую страницу UTF-8 при кодировании текста, написанного с использованием Response.Write.

6
11.11.2009 12:54:08
Это один из тех случаев, когда ответы давным-давно еще пригодились для устаревших проектов.
Dejan Dular 6.09.2018 09:33:26

Не знаю, поможет ли это, но я работал с некоторым классическим ASP- кодом, чтобы использовать утилиту SWFUpload (плагин Flash, который позволяет загружать несколько файлов в пакете).

Пример кода ASP включает в себя некоторый исчерпывающий код, который сортирует декодирование байтов / юникодов и выглядит аналогично тому, что вы упомянули относительно chr (AscB (MidB (... - возможно, просмотр второго примера может пролить свет на вашу проблему).

1
10.11.2009 16:00:30
Кажется, они используют одну и ту же функцию: outPut = outPut & Chr (AscB (MidB (binString, i, 1))). Странно, может, я делаю что-то не так тогда ...
fredrik 10.11.2009 16:18:46

«назад в день», я использовал ASPUpload . Покупать было дешевле, чем тратить время на борьбу с данными форм. Немного похожий на ASP.NET, он делает как обычные поля, так и загруженные файлы доступными для запроса, но он (IIRC) ломает старый объект Form - то есть, как только вы прочитаете из ASPUpload, входной поток будет использован и попытается использовать обычные формы ввода не удастся.

Вы можете использовать оба подхода в одном приложении, но не в обоих случаях при одном и том же запросе страницы; выберите один или другой, в основном (обычно на основе входящего MIME).

1
11.11.2009 13:01:31
Мы фактически использовали ASPUpload один раз, но отошли от него, так как мы всегда забывали устанавливать компонент при установке наших клиентов.
fredrik 11.11.2009 13:39:37
@Marc: Старые входные данные в любом случае будут повреждены при загрузке файла. Объект ASP-формы не знает, как обрабатывать составное тело, поэтому даже если вы не используете входной поток самостоятельно, объект Form все равно будет бесполезен.
AnthonyWJones 11.11.2009 14:29:11
Это было давно - может быть, я имею в виду, что если вы сначала попытаетесь прочитать форму ASP, тогда ASPUpload не будет счастлив? В любом случае: не пытайтесь оба по одному и тому же запросу ;-p
Marc Gravell♦ 11.11.2009 22:59:33