StreamWriter, kodowanie UTF8 i ASCII

0

Witam,

do strumienia dla obiektu HTTPWebRequest request wczytuje content,
który jest uformowanym przeze mnie odpowiednim stringiem
z ciągiem param=value. Niektóre wartości parametrów mogą zawierać
znaki z języka polskiego lub niemieckiego, dlatego chcę ten content
zakodować w UTF-8 a nie ASCII. Gdy koduje w ASCII (przypadek 1.)
wszystko jest OK, jak tylko chce kodowac w UTF-8 (przypadek 2.) to rzucany jest wyjątek
typu ProtocolViolationException:

"Bytes to be written to the stream exceed the Content-Length bytes size specified."

KOD:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URI);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
string contentUTF8 = "zawartość HTTPmessage";
request.ContentLength = contentUTF8.Length;

  1. przypadek
    StreamWriter stOut = new StreamWriter(request.GetRequestStream(), Encoding.ASCII);
    stOut.Write(contentUTF8);
    stOut.Flush();
    stOut.Close();

  2. przypadek
    StreamWriter stOut = new StreamWriter(request.GetRequestStream(), Encoding.UTF8);
    stOut.Write(contentUTF8);
    stOut.Flush() <- rzucany wyjątek ProtocolViolationException
    stOut.Close();

Macie pojęcie, o co może chodzić?

0

mozna wnioskowac z komunikatu, ze podajesz zly rozmiar. Ty podajesz dlugosc napisu (ilosc znakow), a wymagany jest rozmiar w bajtach (w tym przypadku polskie znaki maja po 2 bajty).

0

Użyj metody GetByteCount klasy Encoding aby policzyć ilość bajtów do wysłania lub najpierw zamień wiadomość na tablicę bajtów i w strumieniu wysyłaj bajty.

0

Dzięki. Myślałem wcześniej, że ContentLenght to długość podana w ilości znaków stringa,
a nie byte'ow...

0

Ok, zmodyfikowałem kod i utknąłem w nowym miejscu. Co może tu nie grać?

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(location);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded; charset=utf-8"; 

string contentUTF8 = "Tekst zawierający polski i niemieckie znaki";
byte[] contentUTFbytes = Encoding.UTF8.GetBytes(contentUTF8);
request.ContentLength = contentUTFbytes.Length; //Encoding.UTF8.GetByteCount(contentUTF8); 

StreamWriter stOut = new StreamWriter(request.GetRequestStream(), Encoding.UTF8);            
stOut.Write(contentUTFbytes); 
stOut.Flush();
stOut.Close(); //-> rzucany wyjątek "The request was aborted: The request was canceled." InnerException:"Cannot close stream until all bytes are written.
0

No to zdecyduj się, wysyłasz bajty czy tekst. Na razie wysłałeś bajty jako tekst.
Musisz wysłać
albo tekst (string) przez StreamWriter (aby StreamWriter zakodował odpowiednio tekst),
albo już zakodowany tekst w postaci bajtów bezpośrednio do strumienia.

Zastanów się/doczytaj co to jest dokładnie ten StreamWriter.

0

Za Twoją radą. adf88, potraktowałem całość jako wysyłanie bajtów i teraz działa. Dzięki wielkie.

Oto poprawny kod:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(location);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded; charset=utf-8";

string contentUTF8 = "Tekst zawierający polski i niemieckie znaki";
byte[] contentUTFbytes = Encoding.UTF8.GetBytes(contentUTF8);
request.ContentLength = contentUTFbytes.Length; 

BinaryWriter bnOut = new BinaryWriter(request.GetRequestStream(), Encoding.UTF8);
bnOut.Write(contentUTFbytes);
bnOut.Flush();
bnOut.Close();
0

Eh, prosto do strumienia miało być:

using(Stream requestStream = request.GetRequestStream())
   requestStream.Write(contentUTFbytes);

Poza tym wystarczyło helpa otworzyć: HttpWebRequest.GetRequestStream
tam jest identyczny przykład !!

0

Wznowienie tematu:

a co zrobic, gdy w strumieniu do wysyłki HTTP POST tworze message typu multipart ?
cos jak w HTTPClient w Javie. Jest StringPart i FilePart. Tylko w C# to trzeba zrobic reczenie...

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Uri);
request.Method = "POST";
request.ContentType = "multipart/form-data; boundary=" + Boundary;
request.KeepAlive = true;

byte [] binary_of_file = [0,23,1,42];

string multipart_content = "--" + Boundary + newline +
                        "Content-Disposition: form-data; name=\"filename\"" + newline +
                        "Content-Type: text/plain; charset=UTF-8" + newline +
                        "Content-Transfer-Encoding: 8bit" + newline + newline +

                        "plik_do_wysylli.txt" + newline +                                                                              
                        "--" + Boundary + newline +                        
                        "Content-Disposition: form-data filename=\"" + file_downloaded_from_Synergy.Name + "\"" + newline +
                        "Content-Type: application/octet-stream; charset=UTF-8" + newline +
                        "Content-Transfer-Encoding: binary" + newline + newline +

                        binary_of_file + newline +
                        "--" + Boundary + "--" + newline;

W jaki sposób poznać request.ContetLengh.Length, które będzie pasować tego strumienia?


request.ContetLengh = ???;
StreamWriter stOut = new StreamWriter(request.GetRequestStream(), System.Text.Encoding.ASCII);            
stOut.Write(multipart_content);
stOut.Close();

0

Zasada jest ciągle ta sama - wysyłasz bajty a w ContetLengh podajesz ich ilość.

0

Czy jest w takim razie jakaś metoda, która oblicza ile bajtów, a nie znaków, zajmuje dany string?

0
pytający napisał(a)

Czy jest w takim razie jakaś metoda, która oblicza ile bajtów, a nie znaków, zajmuje dany string?

http://4programmers.net/Forum/494121#id494121

0

Witam,

kontynuując problemy z kodowaniem UTF-8 i wysyłaniem xml w postaci stringu po https.

wysyłam następujący content:

<?xml version="1.0" encoding="UTF-8"?><mainnode><mitemlist><item><id>1651</id><contactemail>[email protected]</contactemail><contactname>Abra, Caßabra</contactname><contactphone>+11(0)2233 444-111</contactphone><text>Verified by XXX->passed</text></item></mitemlist></mainnode>

takim kodem:

UTF8Encoding UTF8_encoding = new UTF8Encoding();
byte[] byte1 = UTF8_encoding.GetBytes(content);                        
request.ContentLength = byte1.Length; 
Stream newStream = request.GetRequestStream();
newStream.Write(byte1, 0, byte1.Length);                        
newStream.Close();
response = (HttpWebResponse)request.GetResponse();

Po podglądnięciu contentu znak '>' jest poprawnie kodowany jako encja '>',
czyli zawartosc zmiennej content to:

<?xml version="1.0" encoding="UTF-8"?><mainnode><mitemlist><item><id>1651</id><contactemail>[email protected]</contactemail><contactname>Abra, Caßabra</contactname><contactphone>+11(0)2233 444-111</contactphone><text>Verified by XXX->passed</text></item></mitemlist></mainnode>

Jednak odbierający serwer ma problem w tym miejscu. String na serwerze urywa się własnie w miejscy tego znaku.

Gdzie leży problem?

Dzięki za jakąkolwiek pomoc.

0

Contenty bez znaku '>' są odbierane przez serwer poprawnie.

0

wez wartosc znacznika Text w CDATA
a w ogole po stronie serwera co parsuje ten xml?

0

Po stronie jest serwera jest jboss i aplikacja napisana w Jave.
Czyli pewnie standardowe biiblioteki Javy do parsowania xmla...

0

Pomysł z

<Text><![CDATA[problematic text with '>' character]]></Text>

nie zdał egazminu...

Po stronie serwera ciąg urywa się przy pierwszym znaku sekcji <![CDATA..., czyli przy '<' z tego ciągu.

Czyżby serwer i prasowanie XML na nim nie obsługiwało nawet CDATA?

0

znaczy parser jest do d...
sprawdz jeszcze tablice bytow, czy po przeksztalceniu na nia zamiast problematycznego > jest > czy to tylko byla kwestia wyswietlania w VS
albo w kontencie jaki przeksztalcasz wpisz > zamiast > i dopiero to do bajtow

0

Według ludzi po stronie serwera ciag przed parsowaniem, cały ciąg jaki odbierają, kończy się w tym miejscu, o którym mówię. Tak jakby coś urywało ciąg podczas przesyłania ciągu przez http.

0

Jeżeli w contencie zamiast '>' umieszczam > wtedy string na serwerze urywa się w miejscu & czyli kolejnego 'zabronionego' znaku. Jakby parser napotykając & od razu urywa ciąg nie analizująć, że jest to encja, jako całość >.

0

Sprawdziłem też dokładnie wysyłaną tablicę bajtów:

w miejsce > wysyłanie jest > bajt po bajcie

[939] 38 byte &
[940] 103 byte g
[941] 116 byte t
[942] 59 byte ;

0

Przed konwersją na tablicę bitów można by spróbować:

content = System.Web.HttpUtility.UrlEncode(content)

Wymaga dodania referencji do System.Web.

1 użytkowników online, w tym zalogowanych: 0, gości: 1