原帖地址:http://www.javashuo.com/article/p-vetxscmu-kb.htmljavascript
涉及网页登陆相关的技术,Cookies确定是忽略不了的。因为项目的须要,要作一个双核的产品。双核间切换会涉及到登陆状态的问题,共享Cookies是一个很好的方案。既然涉及到共享cookies,那么读取完整的cookies和设置cookies就是问题的关键。因为应用自己只须要加载自家的平台,不用考虑共享全部网站cookie的问题,因此须要获取的和设置的cookies相对比较简单。
IE浏览器内核Cookies的获取和设置相对难一点,可是好在网络上资料比较多。Chromium内核基于CEF3框架,获取和设置cookies有现成的接口。在这里主要总结的是IE浏览器内核Cookies的获取和基于CEF3框架的Cookies设置以及获取。
IE浏览器内核的Cookies获取的三种方式:
一、经过读取存在硬盘上的cookies文件,来获取指定网站的cookies;
二、经过用MSHTMLI的Dispatch接口IWebBrowser2和IHTMLDocument2来获取cookies;
三、经过API函数InternetGetCookieEx和InternetGetCookie来获取cookies;
四、经过Hook WINNET 相关的函数获取Cookies,HOOK住发送和接收包API(send、recv、WSASend、WSARecv等)。而后分析HTTP header。此处不讲。
第一种方式,实现起来比较笨重,通常做为后边两种方式的补充。实现代码以下:css
std::wstring GetCookiesUnderIE7( wstring strDomain ) { wstring strCookiePath; TCHAR dataPath[MAX_PATH]; ::SHGetSpecialFolderPath(NULL, dataPath, CSIDL_COOKIES, FALSE); strCookiePath = dataPath; TCHAR szUserName[32]; DWORD cbUserName; cbUserName = 32; GetUserName(szUserName, &cbUserName); WIN32_FIND_DATA FindData; HANDLE hfile; DWORD errorcode = 0; hfile = FindFirstFile((strCookiePath + L"\\*.txt").c_str() ,&FindData); wstring wsUserName = szUserName; wstring wsCookieName = wsUserName + L"@xx"; //xx为网站域名,如百度的baidu wstring wsFileName; wstring wsCookies = L""; hile(hfile!= INVALID_HANDLE_VALUE && errorcode != ERROR_NO_MORE_FILES) { wsFileName = FindData.cFileName; //判断是否存在【user】@xx为名称的cookie脚本,提升过滤效率 if (wsFileName.find(wsCookieName.c_str()) != wstring::npos) { wsFileName = strCookiePath + L"\\"+ FindData.cFileName; //http://www.cnblogs.com/guolixiucai/; std::ifstream ifsCookie(wsFileName.c_str(), std::ios::in | std::ios::binary); if (ifsCookie) { std::string contents; ifsCookie.seekg(0, std::ios::end); contents.resize(ifsCookie.tellg()); ifsCookie.seekg(0, std::ios::beg); ifsCookie.read(&contents[0], contents.size()); if(contents.find("ispass_37wan_com") != string::npos) { wsCookies = s2ws(contents); ifsCookie.close(); break; } ifsCookie.close(); } } BOOL flag = TRUE; BOOL isNextFile = FindNextFile(hfile,&FindData);//判断该目录下是否还有文件 if(flag == TRUE && isNextFile == TRUE)//若是还有文件,则调用SetLastError,设为NO_ERROR,这样才能继续遍历后面的文件 SetLastError(NO_ERROR); else errorcode=GetLastError(); } return wsCookies; }
第二种方式获取的Cookies并不彻底,只能获取到部分Cookies
IHTMLDocument2::get_cookie()
IHTMLDocument2::put_cookie()
用MSHTML对Document对象的Cookie属性进行操做。也能够实现相似InternetGetCookie和InternetSetCookie的效果。实际上它等同于用javascript来读写文档中的Cookie。它一样能够获取、添加、覆盖、修改、删除持久Cookie和会话级Cookie,但不可读写HTTPOnly的Cookie。这种方式一样也要十分注意设置的Cookie的每一个属性都要和目标Cookie一一对应才能正确操做Cookie。特别是Path和Domain属性,不然会致使添加了一个同名Cookie而不能覆盖或清除目标Cookie的结果。
代码以下:html
std::wstring BrowserView::GetCookies() { CComPtr<IWebBrowser2> webBrowser; HRESULT hr = QueryControl(IID_IWebBrowser2, reinterpret_cast<void**>(&webBrowser)); if (FAILED(hr) || (!webBrowser)) return L""; CComPtr<IDispatch> disp; hr = webBrowser->get_Document(&disp); if (FAILED(hr) || (!disp)) return L""; CComPtr<IHTMLDocument2> document; hr = disp->QueryInterface(IID_IHTMLDocument2, reinterpret_cast<void**>(&document)); if (FAILED(hr) || (!document)) return L""; BSTR bstrCookie; hr = document->get_cookie(&bstrCookie); BSTR bstrDomain; document->get_domain(&bstrDomain); if (FAILED(hr)) { return L""; } wstring strCookie(bstrCookie); char* lpszText2 = _com_util::ConvertBSTRToString(bstrCookie); SysFreeString(bstrCookie); return strCookie; }
第三种方式:
InternetGetCookie
InternetSetCookie
InternetGetCookieEx
InternetSetCookieEx
这些API属于Wininet,能够获取、添加、覆盖、修改、删除持久Cookie和会话级Cookie(会话级Cookie须要在同进程中操做)。加Ex后缀的API能够对HTTPOnly的Cookie进行操做。但这组API对IE7及如下的IE浏览器内核无效,取不到Cookies,这时候就须要使用第一种方法补充。固然也可使用其余比较复杂的方法,例如Hook WINNET 相关的函数。java
std::wstring GetCookies( wstring strDomain ) { LPDWORD lpdwSize = new DWORD; wchar_t strCookie[2048] = {0}; int size = 0; //InternetGetCookie 取不到httponly的cookie,留在这里仅供后来者参考 // InternetGetCookie(strDomain.c_str(), NULL, NULL, lpdwSize); // InternetGetCookie(strDomain.c_str(), NULL, strCookie, lpdwSize/*, INTERNET_COOKIE_HTTPONLY, NULL*/); //InternetGetCookieEx 在IE7和IE6里也是取不全cookie。 InternetGetCookieEx(strDomain.c_str(), NULL, strCookie, lpdwSize, 0x2000, NULL); wstring wsCookies = strCookie; return wsCookies; }
CEF3中Cookies的管理。
若是不想听我啰嗦,移步http://magpcss.org/ceforum/apidocs3/projects/(default)/CefCookieManager.html
下边的内容基本上是翻译这个文档,在加上两个实例。
CEF3中,CefCookieManager这个类就是用来管理cookies的。在头文件cef_cookies中,在cef_cookies_capi.h里,有详细的注释,和上边连接里的文档说明同样。
Cookies的管理无外乎Cookies的设置、获取、删除、查找,外加一个存储位置的设置。
class CefCookieManager
extends CefBase
Class used for managing cookies. The methods of this class may be called on any thread unless otherwise indicated.
该类用来管理cookies。除非另有说明,该类的方法能够在任何线程中调用ios
Method Summary | |
static CefRefPtr< CefCookieManager > |
CreateManager( const CefString& path, bool persist_session_cookies, CefRefPtr< CefCompletionCallback > callback ) Creates a new cookie manager. |
virtual bool |
DeleteCookies( const CefString& url, const CefString& cookie_name, CefRefPtr< CefDeleteCookiesCallback > callback )= 0 Delete all cookies that match the specified parameters. |
virtual bool |
FlushStore( CefRefPtr< CefCompletionCallback > callback )= 0 Flush the backing store (if any) to disk. |
static CefRefPtr< CefCookieManager > |
GetGlobalManager( CefRefPtr< CefCompletionCallback > callback ) Returns the global cookie manager. |
virtual bool |
SetCookie( const CefString& url, const CefCookie& cookie, CefRefPtr< CefSetCookieCallback > callback )= 0 Sets a cookie given a valid URL and explicit user-provided cookie attributes. |
virtual bool |
SetStoragePath( const CefString& path, bool persist_session_cookies, CefRefPtr< CefCompletionCallback > callback )= 0 Sets the directory path that will be used for storing cookie data. |
virtual void |
SetSupportedSchemes( const std::vector< CefString >& schemes, CefRefPtr< CefCompletionCallback > callback )= 0 Set the schemes supported by this manager. |
virtual bool |
VisitAllCookies( CefRefPtr< CefCookieVisitor > visitor )= 0 Visit all cookies on the IO thread. |
virtual bool |
VisitUrlCookies( const CefString& url, bool includeHttpOnly, CefRefPtr< CefCookieVisitor > visitor )= 0 Visit a subset of cookies on the IO thread. |
Method Detail
CreateManager
public static CefRefPtr< CefCookieManager > CreateManager( const CefString& path, bool persist_session_cookies, CefRefPtr< CefCompletionCallback > callback );
建立一个新的cookie管理器,当|path|没有被设置时,数据存储在内存中。不然,数据保存在指定的|path|(若是在cef初始化时,指定了缓存路径,那么cookies会保存在此路径)。持久化会话cookies(没有有效期或有效区域),须要设置|persist_session_cookies| 为true。会话cookies通常是暂时性的而且大多数浏览器并不支持。若是|callback| 为 non-NULL ,那么在管理器存储空间初始化后,会在IO线程中异步执行。web
DeleteCookies
public virtual bool DeleteCookies( const CefString& url, const CefString& cookie_name, CefRefPtr< CefDeleteCookiesCallback > callback )= 0;
删除与指定参数的相匹配的全部cookies。若是 |url| 和 |cookie_name| 都被指定,那么 host和domian与这两个参数匹配的都被删除。若是 |url|为空,那么全部的hosts 和domains的cookies都没清空。若是|callback| 为 non-NULL ,那么在cookies被删除后,该回调函数会在IO线程中异步执行。若是不存在指定的url或者cookies不能被访问,那么返回falsh。cookies能够经过交替使用Visit*Cookies()方法被删除。
//向指定的域名删除cookiesapi
void ClientAppBrowser::DeleteCookies( std::wstring domain, std::wstring cookiename ) { CefRefPtr<CefCookieManager> manager = CefCookieManager::GetGlobalManager(NULL); DCHECK(manager.get()); CefRefPtr<CefDeleteCookiesCallback> callback = NULL; std::wstring httpDomain = domain; CefString cookie_name; cookie_name.FromWString(cookiename .c_str()); base::IgnoreResult(&CefCookieManager::DeleteCookies); CefPostTask(TID_IO, NewCefRunnableMethod(manager.get(), &CefCookieManager::DeleteCookies, CefString(httpDomain.c_str()), cookie_name, callback)); }
FlushStore
public virtual bool FlushStore( CefRefPtr< CefCompletionCallback > callback )= 0;
将备份存储(若是存在)缓存到硬盘,若是|callback| 为 non-NULL ,在缓存完后,该回调函数会在IO线程中异步执行。cookies不能被访问则返回falsh。浏览器
GetGlobalManager
public static CefRefPtr< CefCookieManager > GetGlobalManager( CefRefPtr< CefCompletionCallback > callback );
返回全局cookie管理器,默认存储路径是 CefSettings.cache_path或者其余指定路径,不然存储在内存。若是|callback| 为 non-NULL ,在管理器存储空间初始化后,该回调函数会在IO线程中异步执行。该方法与调用CefRequestContext::GetGlobalContext()->GetDefaultCookieManager()至关缓存
SetCookie
public virtual bool SetCookie( const CefString& url, const CefCookie& cookie, CefRefPtr< CefSetCookieCallback > callback )= 0;
设置一个指定了url和由用户设置了属性的cookie。该方法须要每一个属性有符合良好的格式。检查非法字符(例如“;”存在cookie属性值中),存在非法字符会致使cookies设置失败。若是|callback| 为 non-NULL ,那么在cookies被设置后,该回调函数会在IO线程中异步执行。指定的url不存在或者cookies不能被访问,返回falsh。
实例cookie
void ClientAppBrowser::SetCookies( std::wstring domain, std::wstring key, std::wstring svalue ) { /* 向指定的域名写Cookie http://www.cnblogs.com/guolixiucai/ */ CefRefPtr<CefCookieManager> manager = CefCookieManager::GetGlobalManager(NULL); DCHECK(manager.get()); CefRefPtr<CefSetCookieCallback> callback = NULL; CefCookie cookie; CefString(&cookie.name).FromWString(key.c_str()); CefString(&cookie.value).FromWString(svalue.c_str()); CefString(&cookie.domain).FromWString(domain.c_str()); CefString(&cookie.path).FromASCII("/"); cookie.has_expires = true; //如下过时时间随意设置的。 cookie.expires.year = 2200; cookie.expires.month = 4; cookie.expires.day_of_week = 5; cookie.expires.day_of_month = 11; std::wstring httpDomain = L"http://www"; httpDomain.append(domain); base::IgnoreResult(&CefCookieManager::SetCookie); CefPostTask(TID_IO, NewCefRunnableMethod(manager.get(), &CefCookieManager::SetCookie, CefString(httpDomain.c_str()), cookie, callback)); }
SetStoragePath
public virtual bool SetStoragePath( const CefString& path, bool persist_session_cookies, CefRefPtr< CefCompletionCallback > callback )= 0;
设置存储cookies数据的路径。若是|path|为空,则存储在内存中。持久化会话cookies(没有有效期或有效区域),须要设置|persist_session_cookies| 为true。会话cookies通常是暂时性的而且大多数浏览器并不支持。若是|callback| 为 non-NULL ,那么在管理器存储空间初始化后,会在IO线程中异步执行。
SetSupportedSchemes
public virtual void SetSupportedSchemes( const std::vector< CefString >& schemes, CefRefPtr< CefCompletionCallback > callback )= 0;
设置管理器支持的协议。支持常见的协议("http", "https", "ws" and "wss")。若是|callback| 为 non-NULL ,在协议更改生效后,该回调函数会在IO线程中异步执行。该方法必须在全部cookies被访问前调用
VisitAllCookies
public virtual bool VisitAllCookies( CefRefPtr< CefCookieVisitor > visitor )= 0;
访问IO线程中全部的Cookies。返回的cookies按照最长路径排序,而后再按照最长建立时间排序。若是cookies被占用则返回false。
VisitUrlCookies
public virtual bool VisitUrlCookies( const CefString& url, bool includeHttpOnly, CefRefPtr< CefCookieVisitor > visitor )= 0;
访问IO线程上的一组Cookie。返回结果可按照url、host、domain和路径过滤。若是|includeHttpOnly|为ture,那么结果中还会包含HTTP-only cookies。返回的cookies按照最长路径排序,而后再按照最长建立时间排序。若是cookies被占用则返回false。