引言

在C#中,我们通常会使用HttpWebRequest来访问url资源,例子如下:

publicstaticstringGetContentFromUrl(stringurl){HttpWebResponseresponse=null;WebRequestrequest;try{request=WebRequest.Create(url);//makesureitacceptgziprequest.Headers.Set("Accept-Encoding","gzip,deflate");request.Timeout=100000;response=(HttpWebResponse)request.GetResponse();StreamresponseStream=response.GetResponseStream();stringsXML=null;StreamunzipStream=null;StreamReaderoutSr=null;switch(response.ContentEncoding){case"gzip"://getthegzipstreamandunzippedunzipStream=newGZipStream(responseStream,CompressionMode.Decompress);outSr=newStreamReader(unzipStream);break;case"deflate":unzipStream=newDeflateStream(responseStream,CompressionMode.Decompress);outSr=newStreamReader(unzipStream);break;default:outSr=newStreamReader(responseStream);break;}sXML=outSr.ReadToEnd();response.Close();}catch(WebExceptionex){Console.WriteLine(ex.Message);}returnnull;}

当遇到HttpStatusCode>400时,通常会被认为是WebException,错误消息会带上StatusCode如

The remote server returned an error: (401) Unauthorized.

有时候,当401发生时,服务器会在Response里告诉你具体的错误信息,如

<XOIException><StatusCode>40100</StatusCode><StatusMessage>Unknown login error</StatusMessage></XOIException>


因为HttpWebRequest类会把HttpStatusCode>=400当做WebException,这样的话我们就无法获取到Response Stream中的内容啦。


怎样才能获取具体的错误信息,然后根据错误信息做具体的处理呢?


我们可以通过Socket来访问url资源,下面是具体实现的类


RequestHeader

namespaceCom.Morningstar.EquityData.XOIAccessor.Http{publicstaticclassRequestHeader{publicconststringHost="Host";publicconststringAcceptEncoding="Accept-Encoding";publicconststringAcceptLanguage="Accept-Language";publicconststringAccept="Accept";publicconststringConnection="Connection";publicconststringCookie="Cookie";publicconststringUserAgent="User-Agent";publicconststringContentType="Content-Type";publicconststringContentLength="Content-Length";}publicstaticclassResponseHeader{publicstaticstringContentLength="Content-Length";publicstaticstringContentType="Content-Type";publicstaticstringContentEncoding="Content-Encoding";publicstaticstringSetCookie="Set-Cookie";}publicstaticclassConnection{publicstaticstringKeepAlive="Keep-Alive";publicstaticstringClose="Close";}}

HttpMethod

namespaceCom.Morningstar.EquityData.XOIAccessor.Http{publicenumHttpMethod{GET,POST}}

HttpException

namespaceCom.Morningstar.EquityData.XOIAccessor.Http{publicclassHttpException:Exception{publicHttpException(stringmessage):base(message){}publicHttpException(stringmessage,ExceptioninnerException):base(message,innerException){}}}

HttpRequest:建立Http请求,并且返回HttpResponse

namespaceCom.Morningstar.EquityData.XOIAccessor.Http{publicclassHttpRequest{internalHttpRequest(){}publicstringHost{set;get;}privateintport=80;publicintPort{set{if(port>0){port=value;}}get{returnport;}}privateHttpMethodmethod=HttpMethod.GET;publicHttpMethodMethod{set{method=value;}get{returnmethod;}}privatestringpath="/";publicstringPath{set{path=value;}get{returnpath;}}privateNameValueCollectionheaders=newNameValueCollection();publicNameValueCollectionHeaders{set{headers=value;}get{returnheaders;}}publicvoidAddHeader(stringname,stringvalue){headers[name]=value;}publicstringBody{set;get;}///<summary>///Millsecondstowaitresponse///</summary>privateinttimeout=-1;//NevertimeoutpublicintTimeout{set{if(timeout<-1){thrownewArgumentOutOfRangeException("Timeoutislessthan-1");}timeout=value;}get{returntimeout;}}privatevoidCheckReqiredParameters(){if(string.IsNullOrEmpty(Host)){thrownewArgumentException("Hostisblank");}}publicstringBuilSocketRequest(){StringBuilderrequestBuilder=newStringBuilder();FillHeader();BuildRequestLine(requestBuilder);BuildRequestHeader(requestBuilder);BuildRequestBody(requestBuilder);returnrequestBuilder.ToString();}privatevoidFillHeader(){if(Method.Equals(HttpMethod.POST)){if(string.IsNullOrEmpty(Headers[RequestHeader.ContentType])){Headers[RequestHeader.ContentType]="application/x-www-form-urlencoded";}if(!string.IsNullOrEmpty(Body)&&string.IsNullOrEmpty(Headers[RequestHeader.ContentLength])){Headers[RequestHeader.ContentLength]=Encoding.Default.GetBytes(Body).Length.ToString();}}if(!string.IsNullOrEmpty(Headers[RequestHeader.Connection])){Headers[RequestHeader.Connection]=Connection.Close;}if(string.IsNullOrEmpty(Headers[RequestHeader.Accept])){Headers[RequestHeader.Accept]="text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";}if(string.IsNullOrEmpty(Headers[RequestHeader.UserAgent])){Headers[RequestHeader.UserAgent]="Mozilla/5.0(WindowsNT6.1;IE9.0)";}if(string.IsNullOrEmpty(Headers[RequestHeader.AcceptEncoding])){Headers[RequestHeader.AcceptEncoding]="gzip,deflate";}if(string.IsNullOrEmpty(Headers[RequestHeader.Host])){Headers[RequestHeader.Host]=Host;}}privatevoidBuildRequestLine(StringBuilderrequestBuilder){if(Method.Equals(HttpMethod.POST)){requestBuilder.AppendLine(string.Format("POST{0}HTTP/1.1",Path));}else{requestBuilder.AppendLine(string.Format("GET{0}HTTP/1.1",Path));}}privatevoidBuildRequestHeader(StringBuilderrequestBuilder){foreach(stringnameinHeaders){requestBuilder.AppendLine(string.Format("{0}:{1}",name,Headers[name]));}}privatevoidBuildRequestBody(StringBuilderrequestBuilder){requestBuilder.AppendLine();if(!string.IsNullOrEmpty(Body)){requestBuilder.Append(Body);}}publicHttpResponseGetResponse(){CheckReqiredParameters();HttpResponsehttpResponse=newHttpResponse();stringsocketRequest=BuilSocketRequest();byte[]requestBytes=Encoding.ASCII.GetBytes(socketRequest);try{using(Socketsocket=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp)){socket.ReceiveTimeout=Timeout;socket.Connect(Host,Port);if(socket.Connected){socket.Send(requestBytes);ParseResponseLine(socket,httpResponse);ParseResponseHeader(socket,httpResponse);ParseResponseBody(socket,httpResponse);socket.Close();}}}catch(Exceptione){thrownewHttpException("Getresponsefailure.Host:"+Host+",Port:"+Port+",RequestString:"+socketRequest,e);}returnhttpResponse;}privatevoidParseResponseLine(Socketsocket,HttpResponseresponse){stringresponseLine=ReceiveCharBytes(socket,"\r\n");responseLine=responseLine.Replace("\r\n","");string[]fields=responseLine.Split('');if(fields.Length>=3){response.StatusCode=fields[1];response.StatusDescription=responseLine.Substring(responseLine.IndexOf(fields[1])+fields[1].Length+1);}else{thrownewHttpException("Theresponseline:'"+responseLine+"'hasthewrongformat.");}}privatevoidParseResponseHeader(Socketsocket,HttpResponseresponse){stringresponseHeader=ReceiveCharBytes(socket,"\r\n\r\n");string[]headerArry=Regex.Split(responseHeader,"\r\n");if(headerArry!=null){foreach(stringheaderinheaderArry){if(!string.IsNullOrEmpty(header)){intstart=header.IndexOf(":");if(start>0){stringname=header.Substring(0,start);stringvalue="";if(header.Length>start+2){value=header.Substring(start+2);}response.AddHeader(name,value);}}}}}privatestringReceiveCharBytes(Socketsocket,stringbreakFlag){StringBuilderbuilder=newStringBuilder();while(true){byte[]buff=newbyte[1];intread=socket.Receive(buff,SocketFlags.None);if(read>0){builder.Append((char)buff[0]);}if(builder.ToString().EndsWith(breakFlag)){break;}}returnbuilder.ToString();}privatevoidParseResponseBody(Socketsocket,HttpResponseresponse){stringcontentLen=response.GetHeader(ResponseHeader.ContentLength);boolbodyDone=false;if(!string.IsNullOrEmpty(contentLen)){intlen=Convert.ToInt32(contentLen);if(len>0){byte[]contentBytes=newbyte[len];if(socket.Receive(contentBytes)>0){response.Body=contentBytes;}bodyDone=true;}}if(!bodyDone){List<byte[]>readsList=newList<byte[]>();inttotalLength=0;while(true){byte[]buff=newbyte[1024];intreadLen=socket.Receive(buff);if(readLen>0){totalLength+=readLen;byte[]reads=newbyte[readLen];Array.Copy(buff,0,reads,0,readLen);readsList.Add(reads);}else{break;}}byte[]fullBytes=newbyte[totalLength];intindex=0;foreach(byte[]readsinreadsList){Array.Copy(reads,0,fullBytes,index,reads.Length);index+=reads.Length;}response.Body=fullBytes;}}privatestringGetResponseHeader(Socketsocket){StringBuilderbuilder=newStringBuilder();while(true){byte[]buff=newbyte[1];intread=socket.Receive(buff,SocketFlags.None);if(read>0){builder.Append((char)buff[0]);}if(builder.ToString().Contains("\r\n\r\n")){break;}}returnbuilder.ToString();}publicstaticHttpRequestCreate(stringurl){Uriuri=newUri(url);HttpRequestrequest=newHttpRequest();request.Host=uri.Host;request.Port=uri.Port;request.Path=uri.PathAndQuery;returnrequest;}}}

HttpResponse:对Http的响应流进行封装

namespaceCom.Morningstar.EquityData.XOIAccessor.Http{publicclassHttpResponse{internalHttpResponse(){}#regionResponseLinepublicstringStatusCode{internalset;get;}publicstringStatusDescription{internalset;get;}#endregion#regionResponseHeadersprivateNameValueCollectionheaders=newNameValueCollection();publicNameValueCollectionHeaders{get{returnheaders;}}internalvoidAddHeader(stringname,stringvalue){headers[name]=value;}publicstringGetHeader(stringname){returnheaders[name];}publiclong?ContentLength{get{if(!string.IsNullOrEmpty(GetHeader(ResponseHeader.ContentLength))){returnConvert.ToInt64(GetHeader(ResponseHeader.ContentLength));}returnnull;}}publicstringContentEncoding{get{returnGetHeader(ResponseHeader.ContentEncoding);}}#endregionpublicbyte[]Body{internalset;get;}publicStreamGetBodyStream(){if(Body!=null){returnnewMemoryStream(Body);}returnnull;}}}


如何使用HttpRequest类

publicstringGetContent(stringurl){Login();HttpRequestrequest=HttpRequest.Create(url);request.Method=HttpMethod.GET;request.AddHeader(RequestHeader.AcceptEncoding,"gzip,deflate");request.AddHeader(RequestHeader.Cookie,AuthCookie);request.Timeout=Timeout;HttpResponseresp=request.GetResponse();stringxoiErrorCode=resp.GetHeader("X-XOI-ErrorCode");if(!string.IsNullOrEmpty(xoiErrorCode)){if(!xoiErrorCode.Equals(XOIErrorCode.XOI_EC_40401)){XOIExceptionxoiException=newXOIException("Getcontentfail.Url:"+url);stringerrorContent=ReadContent(resp);XmlDocumentdoc=newXmlDocument();doc.LoadXml(errorContent);XmlNodestatusCodeNode=doc.SelectSingleNode(@"/XOIException/StatusCode");XmlNodestatusMessageNode=doc.SelectSingleNode(@"/XOIException/StatusMessage");if(statusCodeNode!=null){xoiException.XOIErrorCode=statusCodeNode.Value;}if(statusMessageNode!=null){xoiException.XOIErrorInfo=statusMessageNode.Value;}throwxoiException;}else{returnstring.Empty;}}returnReadContent(resp);}protectedstringReadContent(HttpResponseresp){StreamReaderreader=null;try{switch(resp.ContentEncoding){case"gzip":reader=newStreamReader(newGZipStream(resp.GetBodyStream(),CompressionMode.Decompress));break;case"deflate":reader=newStreamReader(newDeflateStream(resp.GetBodyStream(),CompressionMode.Decompress));break;default:reader=newStreamReader(resp.GetBodyStream());break;}returnreader.ReadToEnd();}finally{if(reader!=null){reader.Close();}}}