极光推送服务器用的SSL协议版本是TLS1.2,而TLS 1.2 必须要 .NET 4.5或以上版本,然而XP系统是不支持 .NET 4.5或以上版本的。解决方法就是http请求弃用.NET自带的WebRequest,自己使用TCP写HTTPS请求。
两篇参考文章:
.net2.0用TLS1.2+TCP Stream访问https网站
http://blog.csdn.net/atceedsun/article/details/50443657
C# 使用TCPCLIENT模拟HTTP请求的使用
http://www.cnblogs.com/orange-huihui/articles/3266224.html
我的具体做法:
1.cn.jpush.api引用第一篇参考文章里提到的第三方库BouncyCastle.dll;
2.cn.jpush.api的common文件夹下增加一个自定义http请求类,代码如下:
using Org.BouncyCastle.Crypto.Tls;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
namespace cn.jpush.api.common
{
// Need class with TlsClient in inheritance chain
class MyTlsClient : DefaultTlsClient
{
public override TlsAuthentication GetAuthentication()
{
return new MyTlsAuthentication();
}
}
// Need class to handle certificate auth
class MyTlsAuthentication : TlsAuthentication
{
public TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
{
// return client certificate
return null;
}
public void NotifyServerCertificate(Certificate serverCertificate)
{
// validate server certificate
}
}
public class MyHttp
{
public static Response HTTP(string _type, string _url, String _auth = "", string _postdata = "", string _cookie = "")
{
Encoding _responseEncode = Encoding.UTF8;
int port = 80;
try
{
if (_url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
{
port = 443;
}
else
{ }
Uri URI = new Uri(_url);
TcpClient tcpClient = new TcpClient(URI.Host, port);
TlsClientProtocol protocol = new TlsClientProtocol(tcpClient.GetStream(), new Org.BouncyCastle.Security.SecureRandom());
MyTlsClient client = new MyTlsClient();
protocol.Connect(client);
//utf8编码
byte[] bs = UTF8Encoding.UTF8.GetBytes(_postdata);
StringBuilder RequestHeaders = new StringBuilder();
RequestHeaders.Append(_type + " " + URI.PathAndQuery + " HTTP/1.1\r\n");
//RequestHeaders.Append("Content-Type: application/x-www-form-urlencoded\r\n");
//RequestHeaders.Append("User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11\r\n");
//RequestHeaders.Append("Cookie: " + _cookie + "\r\n");
//RequestHeaders.Append("Accept: */*\r\n");
RequestHeaders.Append("Host: " + URI.Host + "\r\n");
RequestHeaders.Append("Content-Length: " + bs.Length + "\r\n");
//RequestHeaders.Append("Connection: close\r\n");
if (!String.IsNullOrEmpty(_auth))
{
RequestHeaders.Append("Authorization: " + "Basic " + _auth + "\r\n");
}
RequestHeaders.Append("\r\n");
byte[] request = Encoding.UTF8.GetBytes(RequestHeaders.ToString() + _postdata);
//发送http请求
protocol.Stream.Write(request, 0, request.Length);
protocol.Stream.Flush();
//读取返回内容
MemoryStream ms = new MemoryStream();
byte[] buffer = new byte[1024000];
int actual = 0;
//先保存到内存流MemoryStream中
try
{
if ((actual = protocol.Stream.Read(buffer, 0, 1024000)) > 0)
{
ms.Write(buffer, 0, actual);
}
}
catch { }
ms.Position = 0;
byte[] bImageBytes = ms.ToArray();
string result = Encoding.UTF8.GetString(bImageBytes);
//Console.WriteLine(result);
int headerIndex = result.IndexOf("\r\n\r\n");
string[] headerStr = result.Substring(0, headerIndex).Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
Dictionary<string, string> responseHeader = new Dictionary<string, string>();
for (int i = 0; i < headerStr.Length; i++)
{
string[] temp = headerStr[i].Split(new string[] { ": " }, StringSplitOptions.RemoveEmptyEntries);
if (temp.Length == 2)
{
if (responseHeader.ContainsKey(temp[0]))
{
responseHeader[temp[0]] = temp[1];
}
else
{
responseHeader.Add(temp[0], temp[1]);
}
}
}
Response response = new Response();
response.HTTPResponseHeader = responseHeader;
string[] httpstatus = headerStr[0].Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
if (httpstatus.Length > 2)
{
response.HTTPStatusCode = httpstatus[1];
}
else
{
response.HTTPStatusCode = "400";
}
response.HTTPResponseText = _responseEncode.GetString(Encoding.UTF8.GetBytes(result.Substring(headerIndex + 4)));
return response;
}
catch
{
return null;
}
}
}
public class Response
{
string hTTPStatusCode;
///
/// http状态代码
///
public string HTTPStatusCode
{
get { return hTTPStatusCode; }
set { hTTPStatusCode = value; }
}
Dictionary<string, string> hTTPResponseHeader;
///
/// Response的header
///
public Dictionary<string, string> HTTPResponseHeader
{
get { return hTTPResponseHeader; }
set { hTTPResponseHeader = value; }
}
string hTTPResponseText;
///
/// html代码
///
public string HTTPResponseText
{
get { return hTTPResponseText; }
set { hTTPResponseText = value; }
}
}
}
3.将cn.jpush.api的common文件夹下的BaseHttpClient.cs里的
public ResponseWrapper sendRequest1(String method, String url, String auth,String reqParams)
方法替换为:
public ResponseWrapper sendRequest(String method, String url, String auth, String reqParams)
{
//结果wrap
ResponseWrapper result = new ResponseWrapper();
try
{
//response
//调用自定义http请求,因为极光推送服务器使用的SSL-TLS1.2版本,必须要.net4.5以上框架才支持,所以只能使用自定义http请求并调用第三方ssl框架实现
Response response = MyHttp.HTTP(method, url, auth, reqParams);
//http status code
HttpStatusCode statusCode = (HttpStatusCode)Convert.ToInt32(response.HTTPStatusCode);
result.responseCode = statusCode;
if (Equals(statusCode, HttpStatusCode.OK))
{
Regex regpatton = new Regex(@"{(.*)}");
MatchCollection jsons = regpatton.Matches(response.HTTPResponseText);
if (jsons.Count > 0)
{
result.responseContent = jsons[0].ToString();
}
String limitQuota = response.HTTPResponseHeader[RATE_LIMIT_QUOTA];
String limitRemaining = response.HTTPResponseHeader[RATE_LIMIT_Remaining];
String limitReset = response.HTTPResponseHeader[RATE_LIMIT_Reset];
result.setRateLimit(limitQuota, limitRemaining, limitReset);
Console.WriteLine("Succeed to get response - 200 OK" + " " + DateTime.Now);
Console.WriteLine("Response Content - {0}", result.responseContent + " " + DateTime.Now);
}
}
catch { }
return result;
}
4.提示有引用问题的,使用修复功能增加相应的引用就成了。
至此,大功告成!
PS:写的比较清楚了,就没有上传完整示例,实在有需要可以向402143909@qq.com索取。