Dane wejściowe nie są prawidłowym ciągiem Base-64, ponieważ zawiera znak inny niż podstawowy 64


105

Mam usługę REST, która odczytuje plik i wysyła go do innej aplikacji konsoli po przekonwertowaniu go na tablicę Byte, a następnie na ciąg Base64. Ta część działa, ale gdy ten sam strumień jest odbierany w aplikacji, jest manipulowany i nie jest już prawidłowym ciągiem Base64. Niektóre postacie śmieci są wprowadzane do strumienia.

Wyjątkiem odebranym podczas konwersji strumienia z powrotem na Byte jest

Dane wejściowe nie są prawidłowym ciągiem Base-64, ponieważ zawierają znak inny niż podstawowy 64, więcej niż dwa znaki uzupełniające lub znak inny niż biały znak wśród znaków uzupełniających

W służbie:

[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;
  }

Przy aplikacji:

       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
Prawdopodobnie ma to związek z Encoding.
Alex Filipovici

1
Czy wiesz, jakie „śmieciowe znaki” są wstawiane?
Jim Mischel,

Zaktualizowany kod jest pomocny. Teraz musimy zobaczyć ciąg, który wysyłasz (np. sW usłudze) i odebraną zawartość (tj result.content. Nie musisz wysyłać całego ciągu, tylko do pierwszego zniekształconego znaku (lub, jeśli jest nadal za długi , podciągi, które pokazują, co zostało wysłane i co otrzymano)
Jim Mischel

@JimMischel yeah, zauważyłem, że „/” jest zastępowane przez „\ /”
Rohit Verma

@RohitVerma W przypadku zastępowania ukośnika, czy jest to w surowej zawartości HTML (Fiddler powie ci), czy w result.Content? Dzięki temu dowiesz się, czy problem dotyczy serwera czy klienta.
Joe Enos

Odpowiedzi:


100

Sprawdź, czy dane obrazu zawierają informacje nagłówka na początku:

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

Spowoduje to powyższy błąd.

Po prostu usuń wszystko przed i łącznie z pierwszym przecinkiem i gotowe.

imageCode = "iVBORw0KGgoAAAANSUhEUgAAAMgAAABkC...

1
Miałem jakoś dokładnie ten problem. Logika polega na usunięciu wszystkiego po tym, ,jak data:jest obecny. Bam. Teraz pracuje.
Maxime Rouiller,

var cleanerBase64 = imageCode.Substring (22); // usuń dane: image / png; base64
mejiamanuel57

3
Tylko trochę kodu, aby pomóc ...... if (this.imageCode.Contains (',')) this.imageCode = this.imageCode.Substring (this.imageCode.IndexOf (",") + 1, this.imageCode.Length - (this.imageCode.IndexOf (",") + 1));
Toby Simmerling,

Użyłbym: .Split (',') [1]
Verthosa

1
str.Substring(str.LastIndexOf(',') + 1)powinien to zrobić.
Alisson

66

Bardzo możliwe, że jest konwertowany do zmodyfikowanego Base64, w którym znaki +i /są zmieniane na -i _. Zobacz http://en.wikipedia.org/wiki/Base64#Implementations_and_history

W takim przypadku musisz to zmienić z powrotem:

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

1
Zrobiłem to ... Dzięki tobie !! Zastąpienie znaków odpowiednimi. Ale czy to jest konkretne rozwiązanie? mam na myśli, jak mogę zagwarantować, że dla wszystkich plików będzie to znak do zastąpienia?
Rohit Verma

2
@RohitVerma: Nie wiem. Musisz dowiedzieć się, gdzie te postacie się zmieniają i określić, czy prawdopodobnie zmieni to jakiekolwiek inne postacie. Nie znam RestSharp, więc nie mogę tam udzielić żadnej porady. Jeśli moja odpowiedź była odpowiedzią na Twoje pytanie, zwyczajowo zaznaczam ją jako zaakceptowaną. (Kliknij znacznik wyboru obok odpowiedzi po lewej stronie.)
Jim Mischel,

OMG Dziękuję! To i dodanie niezbędnych znaków dopełnienia „=” rozwiązało mój problem. Funkcja odszyfrowywania w interfejsie API REST Key Vault platformy Azure wymaga tego procesu i nie dokumentuje go.
used2could

35

Możemy usunąć niepotrzebne ciągi wejściowe poprzedzające wartość.

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

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

To rozwiązanie zadziałało dla mnie. Ale dotyczy to szczególnie obrazów png. Czy istnieje uogólniona składnia, która zastępuje wszystkie rodzaje rozszerzeń graficznych?
Karan Desai

1
przeczytałem teraz twój komentarz. nie próbuję tego, ale możesz użyć tego: hdnImage.Replace ("data: image / png; base64,", String.Empty) .Replace ("data: image / jpg; base64,", String.Empty) .Replace ( "dane: obraz / bmp; base64,", String.Empty); znowu nie próbuję tego. proszę spróbuj i napisz do mnie. zmienię.
Hasan Tuna Oruç

5

Na wypadek, gdybyś nie wiedział, jaki typ przesłanego obrazu, wystarczy usunąć jego base64nagłówek:

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

podzielić i wyświetlić? użyj raczej IndexOf i podciągu
Emmanuel Gleizer

zobacz demeranville.com/…, a pytanie jest również opublikowane tutaj: stackoverflow.com/questions/35388181/…
Emmanuel Gleizer

4

Ponieważ zwracasz ciąg jako JSON, ten ciąg będzie zawierał cudzysłowy otwierające i zamykające w nieprzetworzonej odpowiedzi. Twoja odpowiedź powinna prawdopodobnie wyglądać następująco:

"abc123XYZ=="

czy cokolwiek ... Możesz spróbować to potwierdzić za pomocą Fiddlera.

Domyślam się, że result.Contentjest to nieprzetworzony ciąg znaków zawierający cudzysłowy. W takim przypadku result.Contentkonieczne będzie zdeserializowanie, zanim będzie można z niego korzystać.


masz rację, obejmuje to „”, ale chodzi o to, że oprócz tych cudzysłowów zastępowane są również inne znaki.
Rohit Verma

Deserializacja tego ciągu przy użyciu serializatora JSON zajmie się zarówno cudzysłowami, jak i ukośnikiem. Ucieczka przed ukośnikami w przód jest czymś, co robią niektóre serializatory JSON - użycie deserializatora zmieni \ / z powrotem w zwykły /, dzięki czemu uzyskasz prawidłowy base-64. Ponieważ otrzymujesz JSON, zawsze dobrze jest przeanalizować ten kod JSON poprawnie, nawet jeśli jest to zwykły ciąg.
Joe Enos

3

Ułożyłem podobny kontekst, jaki opisałeś, i napotkałem ten sam błąd. Udało mi się go uruchomić, usuwając "początek i koniec treści i zastępując \/go /.

Oto fragment kodu:

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

Alternatywnie możesz rozważyć użycie XML dla formatu odpowiedzi:

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

Po stronie klienta:

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
Chociaż ten kod może rozwiązać problem, dobra odpowiedź powinna również wyjaśniać, co robi kod i jak pomaga.
BDL

2

Jak wspomniał Alex Filipovici, problemem było nieprawidłowe kodowanie. Plik, który wczytałem, był UTF-8-BOMi wrzuciłem powyższy błąd Convert.FromBase64String(). Zmiana na UTF-8działała bez problemów.


2

Usuń niepotrzebny ciąg za pomocą Regex

Regex regex=new Regex(@"^[\w/\:.-]+;base64,");
base64File=regex.Replace(base64File,string.Empty);

1

Czasami zaczęło się od podwójnych cudzysłowów, najczęściej podczas wywoływania API z dotNetCore 2 w celu pobrania pliku

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

1
Nie można przekonwertować ciągu znaków na bajt []
Urasquirrel

1

Prawdopodobnie ciąg byłby taki, jak ten data:image/jpeg;base64,/9j/4QN8RXh... Pierwszy split dla /i otrzyma drugi token.

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

Następnie podziel się ;i zdobądź pierwszy token, który będzie formatem. W moim przypadku jest to jpeg.

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

Następnie usuń wiersz data:image/jpeg;base64,dotyczący zebranego formatu

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

0

Otrzymuję ten błąd, ponieważ pole było varbinary w tabeli sqlserver zamiast varchar .

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.