Введення не є дійсним рядком Base-64, оскільки він містить неосновний 64 символ


97

У мене є служба REST, яка читає файл і надсилає його в іншу консольну програму після перетворення його в масив байтів, а потім у рядок Base64. Ця частина працює, але коли той самий потік надходить у додаток, він маніпулює і більше не є дійсним рядком Base64. Деякі сміттєві персонажі вводяться в потік.

Винятком, отриманим при перетворенні потоку назад у байт, є

Вхідні дані не є дійсним рядком Base-64, оскільки вони містять неосновний 64 символ, більше двох символів для заповнення або непробіл між символами padding

На службі:

[WebGet(UriTemplate = "ReadFile/Convert", ResponseFormat = WebMessageFormat.Json)]  
public string ExportToExcel()
  {
      string filetoexport = "D:\\SomeFile.xls";
      byte[] data = File.ReadAllBytes(filetoexport);
      var s = Convert.ToBase64String(data);
      return s;
  }

При застосуванні:

       var client = new RestClient("http://localhost:56877/User/");
       var request = new RestRequest("ReadFile/Convert", RestSharp.Method.GET);
       request.AddHeader("Accept", "application/Json");
       request.AddHeader("Content-Type", "application/Json");
       request.OnBeforeDeserialization = resp => {resp.ContentType =    "application/Json";};
       var result = client.Execute(request);
       byte[] d = Convert.FromBase64String(result.Content); 

4
Можливо, це пов’язано з Encoding.
— Алекс Філіпович

1
Ви знаєте, які "сміттєві символи" вставляються?
— Jim Mischel

Оновлений код корисний. Тепер нам потрібно побачити рядок, який ви надсилаєте (тобто sв службі), і отриманий вміст (тобто result.content. Вам не потрібно розміщувати весь рядок, лише до першого спотвореного символу (або, якщо це все ще занадто довго) , деякі підрядки, які показують, що було надіслано, а що отримано).
— Джим Мішель,

@JimMischel так, я помітив, що '/' замінюється на '\ /'
— Рохіт Верма

@RohitVerma Для заміни косої риски це в необробленому вмісті HTML (скаже вам Fiddler) чи в result.Content? Це покаже вам, чи проблема в сервері чи клієнті.
— Джо Енос

Відповіді:


92

Перевірте, чи містять дані зображення на початку інформацію про заголовки:

imageCode = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkC...

Це призведе до вищезазначеної помилки.

Просто видаліть все перед першою комою, включаючи першу кому, і ви готові йти.

imageCode = "iVBORw0KGgoAAAANSUhEUgAAAMgAAABkC...

Була якась така точна проблема. Логіка полягає в тому, щоб видалити все, ,якщо data:є. Бам. Зараз працюю.
— Максим Руйлер

var cleanerBase64 = imageCode.Substring (22); // видалити дані: image / png; base64
— mejiamanuel57,

3
Тільки трохи коду, щоб допомогти ...... if (this.imageCode.Contains (',')) this.imageCode = this.imageCode.Substring (this.imageCode.IndexOf (",") + 1, this.imageCode.Length - (this.imageCode.IndexOf (",") + 1));
— Тобі Сіммерлінг,

Я б використав: .Split (',') [1]
— Вертоса

str.Substring(str.LastIndexOf(',') + 1)повинен це зробити.
— Аліссон,

64

Дуже можливо , це отримання перетворюється в модифікованому Base64, де +і /символи замінюються на -і _. Див. Http://en.wikipedia.org/wiki/Base64#Implementations_and_history

Якщо це так, вам потрібно змінити його назад:

string converted = base64String.Replace('-', '+');
converted = converted.Replace('_', '/');

1
Я це зробив .... Завдяки вам !! Заміна символів на відповідні. Але чи це конкретне рішення? я маю на увазі, як я можу гарантувати, що для всіх файлів це буде символ, який потрібно замінити?
— Rohit Verma

2
@RohitVerma: Не знаю. Вам потрібно з’ясувати, де ці персонажі змінюються, та визначити, чи це може змінити будь-які інші символи. Я не знайомий з RestSharp, тому не можу запропонувати там жодної поради. Якщо моя відповідь відповіла на ваше запитання, прийнято позначати це як прийняту відповідь. (Клацніть галочку біля відповіді ліворуч.)
— Джим Мішель

OMG Дякую! Це та додавання необхідного заповнення символів "=" доповнило мою проблему. Функція розшифровки в Azure Key Vault REST API потребує цього процесу і не документує його.
— used2could

33

Ми можемо видалити непотрібний рядок перед значенням.

string convert = hdnImage.Replace("data:image/png;base64,", String.Empty);

byte[] image64 = Convert.FromBase64String(convert);

Це рішення спрацювало для мене. Але це спеціально для зображень у форматі PNG. Чи існує якийсь узагальнений синтаксис, який замінює всі види розширень зображень?
— Karan Desai

1
я прочитав ваш коментар зараз. я не намагаюся цього, але ви можете використовувати це: hdnImage.Replace ("data: image / png; base64,", String.Empty). Replace ("data: image / jpg; base64,", String.Empty). Replace ( "дані: image / bmp; base64,", String.Empty); ще раз, я не намагаюся це. будь ласка, спробуйте написати мені. я змінюсь.
— Hasan Tuna Oruç

5

Про всяк випадок, коли ви не знаєте тип завантаженого зображення, і вам просто потрібно видалити його base64заголовок:

 var imageParts = model.ImageAsString.Split(',').ToList<string>();
 //Exclude the header from base64 by taking second element in List.
 byte[] Image = Convert.FromBase64String(imageParts[1]);

розділити та до списку? скористайтеся швидше IndexOf та підрядком
— Еммануель Глейзер

див. demeranville.com/…, а запитання також розміщено тут: stackoverflow.com/questions/35388181/…
— Еммануель Гляйзер

4

Оскільки ви повертаєте рядок як JSON, цей рядок включатиме початкові та закриваючі лапки у вихідній відповіді. Тож ваша відповідь, мабуть, повинна виглядати так:

"abc123XYZ=="

чи що завгодно ... Ви можете спробувати підтвердити це за допомогою Скрипаля.

Я припускаю, що result.Contentце необроблений рядок, включаючи лапки. Якщо це так, тоді result.Contentвам доведеться десериалізувати, перш ніж ви зможете ним користуватися.


ви маєте рацію, це включає "", але справа тут у тому, що крім додавання цих лапок замінюються й інші символи.
— Rohit Verma

Десеріалізація цього рядка за допомогою серіалізатора JSON подбає як про лапки, так і про скісну риску. Деякі серіалізатори JSON роблять те, що уникають похилих рисок уперед за допомогою зворотної риски - використання десериалізатора перетворить \ / назад у звичайний / так, що ви отримаєте дійсну базу-64. Оскільки ви отримуєте JSON, завжди гарною ідеєю є проаналізувати цей JSON належним чином, навіть якщо це просто простий рядок.
— Joe Enos

3

Я влаштував подібний контекст, як ви описали, і зіткнувся з тією ж помилкою. Мені вдалося змусити його працювати, видаливши "з початку та кінця вмісту та замінивши \/на /.

Ось фрагмент коду:

var result = client.Execute(request);
var response = result.Content
    .Substring(1, result.Content.Length - 2)
    .Replace(@"\/","/");
byte[] d = Convert.FromBase64String(response);

Як альтернативу, ви можете розглянути можливість використання XML для формату відповіді:

[WebGet(UriTemplate = "ReadFile/Convert", ResponseFormat = WebMessageFormat.Xml)]  
public string ExportToExcel() { //... }

З боку клієнта:

request.AddHeader("Accept", "application/xml");
request.AddHeader("Content-Type", "application/xml");
request.OnBeforeDeserialization = resp => { resp.ContentType = "application/xml"; };

var result = client.Execute(request);
var doc = new System.Xml.XmlDocument();
doc.LoadXml(result.Content);
var xml = doc.InnerText;
byte[] d = Convert.FromBase64String(xml);

3
var spl = item.Split('/')[1];
var format =spl.Split(';')[0];           
stringconvert=item.Replace($"data:image/{format};base64,",String.Empty);

7
Хоча цей код може вирішити проблему, хороша відповідь також повинна пояснити, що робить код і як він допомагає.
— BDL

1

Як згадував Алекс Філіпович, проблема була неправильним кодуванням. Файл, який я прочитав, був UTF-8-BOMі викинув вищевказану помилку Convert.FromBase64String(). Перехід на UTF-8роботу без проблем.


1

І іноді він починався з подвійних лапок, більшість випадків коли ви викликаєте API з dotNetCore 2 для отримання файлу

string string64 = string64.Replace(@"""", string.Empty);
byte[] bytes = Convert.ToBase64String(string64);

1
Неможливо перетворити з рядка в байт []
— Urasquirrel

1

Можливо, рядок буде схожий на цей data:image/jpeg;base64,/9j/4QN8RXh... перший поділ /і отримає другий маркер.

var StrAfterSlash = Face.Split('/')[1];

Потім розділіть ;і отримайте перший маркер, який буде форматом. У моєму випадку це jpeg.

var ImageFormat =StrAfterSlash.Split(';')[0];

Потім видаліть рядок data:image/jpeg;base64,для зібраного формату

CleanFaceData=Face.Replace($"data:image/{ImageFormat };base64,",string.Empty);

1

Видаліть непотрібний рядок за допомогою регулярного виразу

Regex regex=new Regex(@"^[\w/\:.-]+;base64,");
base64File=regex.Replace(base64File,string.Empty);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.