一直以来想要做个程序,将Google Docs用作网盘,程序做得差不多了才发现不是所有的人都可以上传任意类型的文件,只有商业用户才可以。商业用户是要交钱的,这与我们倡导的免费精神相去甚远。怎么办?我的心血不能白费,Google还算厚道没有把门关死,可以通过form的形式上传,我们可以模拟form的动作,就能上传了。
Google在上传时要进行身份验证。取得身份验证后,提出上传要求,这时返回一个上传地址,然后上传文件。下面一步步来:
访问Google Docs获取登录页面: 先访问 http://docs.google.com,它通过自动跳转将你带到一个登录页面。按登录页面中的头部的set-cookie设置HttpWebRequest的cookie,cookie中最重要的是HSID。
提交登录信息:
设置url为 https://www.google.com/accounts/ServiceLoginAuth?service=writely,然后设置提交数据:
ltmpl=homepage&continue=http://docs.google.com/&followup=http://docs.google.com/&service=writely&nui=1&rm=false&dsh={0}<mpl=homepage<mpl=homepage&GALX={1}&Email={2}&Passwd={3}&rmShown=1&signIn=登录&asts=
其中Email填Google帐户名,Passwd填密码,GALX可以从cookie中找到,dsh可从页面的数据中得到。
检查Cookie: 访问网址:https://www.google.com/accounts/CheckCookie,取得下一步的访问地址。
获取认证Cookie:
访问网址:http://docs.google.com/?auth=.......,根据回应设置cookie,这时的cookie就是可以访问相当于doc api中的token了。
关键Cookie:认证后的cookie中包含三条记录HSID、SID、writelySID
private CookieContainer GetAuthenticationCookie(string User,string Passwd)
{
string GALX;
string dsh;
string resText = "";
CookieContainer Auth = new CookieContainer();
//第一步:访问docs.google.com获取登录页面
HttpWebRequest req = CreatRequest("http://docs.google.com/");
req.Method = "POST";
req.ContentLength = 0;
HttpWebResponse res = (HttpWebResponse)req.GetResponse();
//第二步:提取GALX和dsh参数,构造登录数据
resText = getResponseText(res);
GALX = resText.Substring(resText.IndexOf("GALX") + 26, 11);
if ((resText.Substring(resText.IndexOf("dsh") + 32, 1)) == "-")
dsh = resText.Substring(resText.IndexOf("dsh") + 32, 20);
else
dsh = resText.Substring(resText.IndexOf("dsh") + 32, 19);
string postData = string.Format(
"ltmpl=homepage&continue=http://docs.google.com/&followup=http://docs.google.com/&service=writely&nui=1&rm=false&dsh={0}<mpl=homepage<mpl=homepage&GALX={1}&Email={2}&Passwd={3}&rmShown=1&signIn=登录&asts=",
dsh, GALX, User, Passwd);
req = CreatRequest("https://www.google.com/accounts/ServiceLoginAuth?service=writely");
req.AllowAutoRedirect = false;
req.Method = "POST";
//设置cookie及提交数据
Auth.Add(setCookie(res, "www.google.com"));
req.CookieContainer = Auth;
setPostData(req, postData);
res = (HttpWebResponse)req.GetResponse();
//第三步:检查Cookie
req = CreatRequest(res.Headers["Location"]);
Auth.Add(setCookie(res, "www.google.com"));
req.CookieContainer = Auth;
res = (HttpWebResponse)req.GetResponse();
//第四步:获取最终认证Cookie
resText = getResponseText(res);
string url = resText.Substring(resText.IndexOf("url=")).Split('"')[0];
url = HttpUtility.HtmlDecode(url);
url = url.Substring(5, url.Length - 6);
req = CreatRequest(url);
req.Method = "GET";
req.AllowAutoRedirect = false;
Auth.Add(setCookie(res, "www.google.com"));
req.CookieContainer = Auth;
res = (HttpWebResponse)req.GetResponse();
Auth.Add(setCookie(res, "www.google.com"));
return Auth;
}整个过程很简单,但调试花了很长时间,主要是在HTTPS下调试走了很多弯路。一开始使用HttpAnalyzer,结果有bug显示的传送数据总是重复。后来还是使用Fiddler才解决。但使用Fiddler时在HTTPS下会出现证书与网站不符的错误。
解决办法:
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(ValidateServerCertificate);
public static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
return true;
}第一个函数在设置HttpWebRequest时调用就不会出现错误了