Как отключить имена файлов в кодировке base64 в HttpClient/MultipartFormDataContent

Я использую HttpClient для POST MultipartFormDataContent для веб-приложения Java. Я загружаю несколько StringContents и один файл, который я добавляю как StreamContent, используя MultipartFormDataContent.Add(HttpContent content, String name, String fileName), используя метод HttpClient.PostAsync(String, HttpContent).

Это работает нормально, за исключением случаев, когда я предоставляю fileName, который содержит немецкие умляуты (я еще не тестировал другие символы, отличные от ASCII). В этом случае fileName кодируется в base64. Результат для файла с именем 99 2 LD 353 Temp Äüöß-1.txt

выглядит так:

 __utf-8_B_VGVtcCDvv73vv73vv73vv71cOTkgMiBMRCAzNTMgVGVtcCDvv73vv73vv73vv70tMS50eHQ___

Сервер Java показывает это закодированное имя файла в своем пользовательском интерфейсе, что сбивает пользователей с толку. Я не могу вносить какие-либо изменения на стороне сервера.

Как отключить это поведение? Любая помощь будет высоко ценится.

Заранее спасибо!


person Strezz0r    schedule 21.02.2014    source источник


Ответы (4)


Я только что обнаружил то же ограничение, что и StrezzOr, поскольку сервер, который я потреблял, не соблюдал стандарт имени файла *.

Я преобразовал имя файла в массив байтов представления UTF-8 и переоборудовал байты как символы «простой» строки (не UTF-8).

Этот код создает поток контента и добавляет его к составному контенту:

        FileStream fs = File.OpenRead(_fullPath);
        StreamContent streamContent = new StreamContent(fs);
        streamContent.Headers.Add("Content-Type", "application/octet-stream");
        String headerValue = "form-data; name=\"Filedata\"; filename=\"" + _Filename + "\"";
        byte[] bytes = Encoding.UTF8.GetBytes(headerValue);
        headerValue="";
        foreach (byte b in bytes)
        {
            headerValue += (Char)b;
        }
        streamContent.Headers.Add("Content-Disposition", headerValue);
        multipart.Add(streamContent, "Filedata", _Filename);

Это работа с испанским акцентом.

Надеюсь это поможет.

person Ugo Enrico Albarello    schedule 10.03.2015
comment
Обратите внимание, что multipart.Add(streamContent, Filedata, _Filename) не требуется, достаточно multipart.Add(streamContent). В настоящее время multipart.Add(streamContent, Filedata, _Filename) просто пропустит 2 последних аргумента, поскольку заголовок уже существует, но он может измениться в будущем (вместо этого он перезапишет\заменит, если пропустит). - person osexpert; 17.07.2019

Недавно я обнаружил эту проблему, и я использую обходной путь здесь:

На стороне сервера:

private static readonly Regex _regexEncodedFileName = new Regex(@"^=\?utf-8\?B\?([a-zA-Z0-9/+]+={0,2})\?=$");

private static string TryToGetOriginalFileName(string fileNameInput) {
    Match match = _regexEncodedFileName.Match(fileNameInput);
    if (match.Success && match.Groups.Count > 1) {
        string base64 = match.Groups[1].Value;
        try {
            byte[] data = Convert.FromBase64String(base64);
            return Encoding.UTF8.GetString(data);
        }
        catch (Exception) {
            //ignored
            return fileNameInput;
        }
    }
    return fileNameInput;
}

И затем используйте эту функцию следующим образом:

string correctedFileName = TryToGetOriginalFileName(fileRequest.FileName);

Оно работает.

person guogangj    schedule 23.12.2016

В конце концов я сдался и решил задачу, используя HttpWebRequest вместо HttpClient. Мне пришлось создавать заголовки и контент вручную, но это позволило мне игнорировать стандарты для отправки имен файлов, отличных от ASCII. В итоге я впихнул незакодированные имена файлов UTF-8 в заголовок filename, и это был единственный способ, которым сервер мог принять мой запрос.

person Strezz0r    schedule 07.03.2014

Для передачи символов, отличных от ascii, в атрибуте имени файла заголовка Content-Disposition необходимо использовать атрибут filename* вместо обычного filename. См. спецификацию здесь.

Чтобы сделать это с помощью HttpClient, вы можете сделать следующее:

   var streamcontent = new StreamContent(stream);
   streamcontent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") {
      FileNameStar = "99 2 LD 353 Temp Äüöß-1.txt" 
   };
   multipartContent.Add(streamcontent);

Тогда заголовок будет выглядеть так:

  Content-Disposition: attachment; filename*=utf-8''99%202%20LD%20353%20Temp%20%C3%84%C3%BC%C3%B6%C3%9F-1.txt
person Darrel Miller    schedule 21.02.2014
comment
К сожалению, сервер, похоже, не соблюдает имя файла * или он также закодирован в base64, поскольку файл по-прежнему отображается с закодированным именем в пользовательском интерфейсе приложения. Поскольку заголовок вашего примера выглядит в URL-кодировке, я также пытался URL-кодировать имя файла, но веб-приложение покажет его как есть, без декодирования. - person Strezz0r; 04.03.2014