Введення не є дійсним рядком 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.