C++模拟Http/Https访问web站点
一、概述
1.Http与Https的区别与联系
在OSI参考模型中Http与Https均属于应用层协议。Http即Hypertext Transfer Protocol,超文本传输协议;而Https为Secure Hypertext Transfer Protocol安全超文本传输协议,它是一个安全通信通道,基于HTTP开发,用于在客户端与服务器之间交换信息,它使用安全套接字层SSL进行信息交换,简单来说它就是HTTP的安全版。
Http默认使用80端口,Https使用443端口。
Http的数据在网络上是明文传输,而Https则是通过加密后的传输,因此它相比http会更加安全,但是由于需要额外加解密操作,因为Https的效率没有那么高。在登录Https站点和Http站点时,可以明显感觉到性能差异。
2.关于web访问的安全性
当前许多的web站点登录时都是采用普通的http进行传输,这种方式有着极大的安全隐患。当前web开发登录系统常用的有以下四种方式:
1) 账号和密码完全没有加密,明文传送。这种方式的安全级别是最低的,它无疑是将自己的账号和密码直接暴露给别人,通过抓包工具(例:WireShark)可以很容易的截获到账号和密码。
2) 密码采用MD5或其它加密方式进行加密,声称不可破解。其实,完全没有必要破解,只要截获加密后的密码串,就可以以你的身份访问服务器,这样也是可以通过认证授权的。这种方式在加密程度上有了一定程度的提高,但仍是不安全的。
3) 客户端在登录前去服务端拿一次密钥,通过该密钥进行加密,而服务器端的密钥是随机生成的,每次访问均会用不同的密钥。这种方式的安全性比较高。
4) 采用“安全性最高”的HTTPS方式传输,客户端与服务端会经过认证,且中间的传输数据全部进行加密。之所以在安全性最高上加引号,是因为它也不是绝对安全的,比如前段时间Openssl曝出安全漏洞,大名鼎鼎的“心脏出血”,黑客利用它的一个memcpy的bug,可以从溢出的内存中拿到64K的用户数据,导致用户信息泄露。但是这个安全性级别相对前面三个是最高的,当前服务端的证书一年收费大约3-5千,用这点钱换来相对安全,是很划算的事情了。
二、SOCKET发送HTTP请求
1.基本流程
无论是Http还是Https都是基于TCP进行传输的,因此使用SOCKET模拟HTTP访问web站点的方式,很简单,就是将头部数据拼接成数据包,发送给服务端,然后接收返回再解析就可以了。
其基本流程和编写普通SOCKET通信是一样的。Windows下的流程为:
a. WSAStartup对Winsock服务进行初始化
b. 建立socket套接字
c. connect连接服务端
d. send发送数据
e. recv接收数据
下面,以某站点的登录为例,利用Fiddler抓到的POST的头部信息如下:
这样,我们就可以构建这样的数据包发送出去,然后接收响应了,C++实现核心代码请见下部分。
2.核心代码
- BOOL SocketClient::ConnectToServer(const CString strServerUrl, const int nPort)
- {
- cstrServerUrl = strServerUrl;
- nServerPort = nPort;
- BOOL bRet = FALSE;
- do
- {
- if (!InitializeContext())
- {
- break;
- }
- if(!Connect())
- {
- break;
- }
- bRet = TRUE;
- } while (FALSE);
- return bRet;
- }
- BOOL SocketClient::LoginToServer(const CString strUsername, const CString strPasswd)
- {
- cstrUserName = strUsername;
- cstrPassWord = strPasswd;
- BOOL bRet = FALSE;
- do
- {
- if (!SendPostData())
- {
- break;
- }
- bRet = TRUE;
- } while (FALSE);
- return bRet;
- }
- BOOL SocketClient::LogoutOfServer()
- {
- return FALSE;
- }
- BOOL SocketClient::InitializeContext()
- {
- BOOL bRet = FALSE;
- wsaData = new WSADATA;
- WORD wVersion = MAKEWORD(2, 2);
- do
- {
- if(0 != WSAStartup(wVersion, wsaData))
- {
- break;
- }
- if(LOBYTE( wsaData->wVersion ) != 2 || HIBYTE( wsaData->wVersion ) != 2 )
- {
- WSACleanup();
- break;
- }
- LPHOSTENT lpHostTent;
- lpHostTent = gethostbyname(cstrServerUrl);
- if (NULL == lpHostTent)
- {
- break;
- }
- socketClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (socketClient == INVALID_SOCKET)
- {
- WSACleanup();
- break;
- }
- socketAddrClient = new SOCKADDR_IN;
- socketAddrClient->sin_family = AF_INET;
- socketAddrClient->sin_port = htons(nServerPort);
- socketAddrClient->sin_addr = *((LPIN_ADDR)*lpHostTent->h_addr_list);
- memset(socketAddrClient->sin_zero, 0, sizeof(socketAddrClient->sin_zero));
- bRet = TRUE;
- } while (FALSE);
- return bRet;
- }
- BOOL SocketClient::Connect()
- {
- BOOL bRet = FALSE;
- do
- {
- if (SOCKET_ERROR == connect(socketClient, (LPSOCKADDR)socketAddrClient, sizeof(SOCKADDR_IN)))
- {
- int nErrorCode = WSAGetLastError();
- closesocket(socketClient);
- break;
- }
- bRet = TRUE;
- } while (FALSE);
- return bRet;
- }
- BOOL SocketClient::SendPostData()
- {
- CString cstrSendData;
- CString cstrSendParam = "redirect=&username="+cstrUserName+"&password="+cstrPassWord+"&auto_login=checked&submit=%E7%99%BB%E5%BD%95";
- BOOL bRet = FALSE;
- CString cstrSendParamLen;
- cstrSendParamLen.Format("%d", cstrSendParam.GetLength());
- cstrSendData = "POST http://account.vsochina.com/user/login HTTP/1.1\r\n";
- cstrSendData += "Host: account.vsochina.com\r\n";
- cstrSendData += "User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0\r\n";
- cstrSendData += "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
- cstrSendData += "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
- cstrSendData += "Accept-Encoding: gzip, deflate\r\n";
- cstrSendData += "DNT: 1\r\n";
- cstrSendData += "Referer: http://account.vsochina.com/user/login\r\n";
- cstrSendData += "Connection: keep-alive\r\n";
- cstrSendData += "Content-Type: application/x-www-form-urlencoded\r\n";
- cstrSendData += "Content-Length: " + cstrSendParamLen +"\r\n";
- cstrSendData += "\r\n";
- cstrSendData += cstrSendParam;
- CString cstrRecvData;
- do
- {
- if (-1 == send(socketClient, cstrSendData.GetBuffer(), cstrSendData.GetLength(), 0))
- {
- break;
- }
- char recvData[1000] = {0};
- int nRecvLen;
- while((nRecvLen = recv(socketClient, recvData, sizeof(recvData), 0)) > 0)
- {
- cstrRecvData += recvData;
- }
- if (cstrRecvData.GetLength() == 0)
- {
- break;
- }
- ParseCookieFromRecvData(cstrRecvData);
- //!判断返回的COOKIE信息中,UID是否存在
- if (cstrCookieUid.IsEmpty())
- {
- break;
- }
- bRet = TRUE;
- } while (FALSE);
- return bRet;
- }
- void SocketClient::ParseCookieFromRecvData(const CString cstrRecvData)
- {
- list<CString> lstCookiesLine; //!存放Set-Cookie的一行,例:Set-Cookie: vso_uname=houqd_1111;
- CString cstrFind = "Set-Cookie:"; //!查找标记
- CString cstrSeperator = "\r\n"; //!以"\r\n"分割号来分割字符串
- int nPos = 0;
- int nStart = cstrRecvData.Find(cstrSeperator);
- while(nStart != -1)
- {
- CString cstrSessionLine = cstrRecvData.Mid(nPos, nStart - nPos + 1);
- if (cstrSessionLine.Find(cstrFind) != -1)
- {
- CString cstrRealRecord = cstrSessionLine.Right(cstrSessionLine.GetLength() - cstrFind.GetLength() - 3);
- list<CString>::iterator it = find(lstCookiesLine.begin(), lstCookiesLine.end(), cstrRealRecord);
- if (it == lstCookiesLine.end())
- {
- lstCookiesLine.push_back(cstrRealRecord);
- }
- }
- nPos = nStart;
- nStart = cstrRecvData.Find(cstrSeperator, nPos + 2);
- }
- //!根据每行获取的cookie值,解析为key-value的形式
- vector<CString> vecCookieSet;
- for (list<CString>::iterator it = lstCookiesLine.begin(); it != lstCookiesLine.end(); it++)
- {
- CString cstrCookies = *it;
- CString cstrSeperator = ";";
- StaticUtility::StringSplit(cstrCookies, cstrSeperator, vecCookieSet);
- }
- vector<CString> vecTemp;
- for (vector<CString>::iterator it = vecCookieSet.begin(); it != vecCookieSet.end(); it++)
- {
- vecTemp.clear();
- CString cstrOneCookies = *it;
- CString cstrSeperator = "=";
- StaticUtility::StringSplit(cstrOneCookies, cstrSeperator, vecTemp);
- CString cstrKey = vecTemp[0];
- CString cstrVal = vecTemp[1];
- if(cstrKey.Compare("vso_uid") == 0)
- {
- cstrCookieUid = cstrVal;
- break;
- }
- }
- }
通过接收来的头部信息中,将cookie信息解析出来,就可以判断是否登录成功了。然后,如果有或许的操作,在请求中挂上这些cookie信息,就可以获取想要的数据,完成想要的操作了。
三、OpenSSL发送HTTPS请求
1.基本流程
HTTPS=HTTP + SSL,因此利用OpenSSL发送请求给HTTPS站点和第二章的SOCKET发送HTTP是非常相似的,只不过要在原生的套接字上套上SSL层,基本流程如下:
a. WSAStartup对Winsock服务进行初始化
b. 建立socket套接字
c. connect连接服务端
d. 建立SSL上下文
e. 建立SSL
f. 将SSL与前面建立的socket套接字绑定
g. SSL_write()发送数据
h. SSL_read()接收数据
下面以小米官网站点的登录为例,来展示利用OpenSSL如何访问HTTPS站点,模拟登陆,核心代码,见下一章节。
2.核心代码
- #pragma comment( lib, "libeay32.lib" )
- #pragma comment( lib, "ssleay32.lib" )
- HttpsClient::HttpsClient(void):
- wsaData(NULL),
- socketAddrClient(NULL),
- ssl(NULL),
- sslCtx(NULL),
- sslMethod(NULL),
- serverCertification(NULL)
- {
- SSL_load_error_strings();
- SSLeay_add_ssl_algorithms();
- }
- HttpsClient::~HttpsClient(void)
- {
- //!清理打开的句柄
- if (NULL != ssl)
- {
- SSL_shutdown(ssl);
- closesocket(socketClient);
- SSL_free(ssl);
- ssl = NULL;
- }
- if (NULL != sslCtx)
- {
- SSL_CTX_free(sslCtx);
- }
- WSACleanup();
- }
- BOOL HttpsClient::ConnectToServer(const CString strServerUrl, const int nPort)
- {
- cstrServerUrl = strServerUrl;
- nServerPort = nPort;
- BOOL bRet = FALSE;
- do
- {
- if (!InitializeSocketContext())
- {
- break;
- }
- if (!SocketConnect())
- {
- break;
- }
- if (!InitializeSslContext())
- {
- break;
- }
- if (!SslConnect())
- {
- break;
- }
- bRet = TRUE;
- } while (FALSE);
- return bRet;
- }
- BOOL HttpsClient::LoginToServer(const CString strUsername, const CString strPasswd)
- {
- cstrUserName = strUsername;
- cstrPassWord = strPasswd;
- BOOL bRet = FALSE;
- do
- {
- if (!SendLoginPostData())
- {
- break;
- }
- CString cstrRecvData;
- RecvLoginPostData(cstrRecvData);
- if (cstrRecvData.GetLength() == 0)
- {
- break;
- }
- ParseCookieFromRecvData(cstrRecvData);
- if (cstrCookieUid.IsEmpty() || cstrCookieUid.Compare("EXPIRED") == 0)
- {
- break;
- }
- bRet = TRUE;
- } while (FALSE);
- return bRet;
- }
- BOOL HttpsClient::LogoutOfServer()
- {
- return FALSE;
- }
- BOOL HttpsClient::InitializeSocketContext()
- {
- //!初始化winSocket环境
- BOOL bRet = FALSE;
- wsaData = new WSADATA;
- WORD wVersion = MAKEWORD(2, 2);
- do
- {
- if(0 != WSAStartup(wVersion, wsaData))
- {
- break;
- }
- if(LOBYTE( wsaData->wVersion ) != 2 || HIBYTE( wsaData->wVersion ) != 2 )
- {
- WSACleanup();
- break;
- }
- LPHOSTENT lpHostTent;
- lpHostTent = gethostbyname(cstrServerUrl);
- if (NULL == lpHostTent)
- {
- break;
- }
- socketClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (socketClient == INVALID_SOCKET)
- {
- WSACleanup();
- break;
- }
- socketAddrClient = new SOCKADDR_IN;
- socketAddrClient->sin_family = AF_INET;
- socketAddrClient->sin_port = htons(nServerPort);
- socketAddrClient->sin_addr = *((LPIN_ADDR)*lpHostTent->h_addr_list);
- memset(socketAddrClient->sin_zero, 0, sizeof(socketAddrClient->sin_zero));
- bRet = TRUE;
- } while (FALSE);
- return bRet;
- }
- BOOL HttpsClient::SocketConnect()
- {
- //!原生socket连接
- BOOL bRet = FALSE;
- do
- {
- if (SOCKET_ERROR == connect(socketClient, (LPSOCKADDR)socketAddrClient, sizeof(SOCKADDR_IN)))
- {
- int nErrorCode = WSAGetLastError();
- closesocket(socketClient);
- break;
- }
- bRet = TRUE;
- } while (FALSE);
- return bRet;
- }
- BOOL HttpsClient::InitializeSslContext()
- {
- //!SSL通信初始化
- BOOL bRet = FALSE;
- do
- {
- sslMethod = SSLv23_client_method();
- if(NULL == sslMethod)
- {
- break;
- }
- sslCtx = SSL_CTX_new(sslMethod);
- if (NULL == sslCtx)
- {
- break;
- }
- ssl = SSL_new(sslCtx);
- if (NULL == ssl)
- {
- break;
- }
- bRet = TRUE;
- } while (FALSE);
- return bRet;
- }
- BOOL HttpsClient::SslConnect()
- {
- //!SSL绑定原生socket,并连接服务器
- BOOL bRet = FALSE;
- do
- {
- SSL_set_fd(ssl, socketClient);
- int nRet = SSL_connect(ssl);
- if (-1 == nRet)
- {
- break;
- }
- bRet = TRUE;
- } while (FALSE);
- return bRet;
- }
- BOOL HttpsClient::SslGetCipherAndCertification()
- {
- BOOL bRet = FALSE;
- do
- {
- cstrSslCipher = SSL_get_cipher(ssl);
- serverCertification = SSL_get_certificate(ssl);
- if (NULL == serverCertification)
- {
- break;
- }
- cstrSslSubject = X509_NAME_oneline(X509_get_subject_name(serverCertification), 0, 0);
- cstrSslIssuer = X509_NAME_oneline(X509_get_issuer_name(serverCertification), 0, 0);
- X509_free(serverCertification);
- bRet = TRUE;
- } while (FALSE);
- return bRet;
- }
- BOOL HttpsClient::SendLoginPostData()
- {
- CString cstrSendData;
- //CString cstrSendParam = "redirect=&username="+cstrUserName+"&password="+cstrPassWord+"&auto_login=checked&submit=%E7%99%BB%E5%BD%95";
- CString cstrSendParam = "user="+cstrUserName+"&_json=true&pwd="+cstrPassWord+"&callback=http%3A%2F%2Forder.mi.com%2Flogin%2Fcallback%3Ffollowup%3Dhttp%253A%252F%252Fwww.mi.com%252F%26sign%3DNWU4MzRmNjBhZmU4MDRmNmZkYzVjMTZhMGVlMGFmMTllMGY0ZTNhZQ%2C%2C&sid=mi_eshop&qs=%253Fcallback%253Dhttp%25253A%25252F%25252Forder.mi.com%25252Flogin%25252Fcallback%25253Ffollowup%25253Dhttp%2525253A%2525252F%2525252Fwww.mi.com%2525252F%252526sign%25253DNWU4MzRmNjBhZmU4MDRmNmZkYzVjMTZhMGVlMGFmMTllMGY0ZTNhZQ%25252C%25252C%2526sid%253Dmi_eshop&hidden=&_sign=%2Bw73Dr7cAfRlMfOR6fW%2BF0QG4jE%3D&serviceParam=%7B%22checkSafePhone%22%3Afalse%7D&captCode=";
- BOOL bRet = FALSE;
- CString cstrSendParamLen;
- cstrSendParamLen.Format("%d", cstrSendParam.GetLength());
- cstrSendData = "POST https://account.xiaomi.com/pass/serviceLoginAuth2 HTTP/1.1\r\n";
- cstrSendData += "Host: account.xiaomi.com\r\n";
- cstrSendData += "User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0\r\n";
- cstrSendData += "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
- cstrSendData += "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
- cstrSendData += "Accept-Encoding: gzip, deflate\r\n";
- cstrSendData += "DNT: 1\r\n";
- cstrSendData += "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n";
- cstrSendData += "Referer: https://account.xiaomi.com/pass/serviceLogin?callback=http%3A%2F%2Forder.mi.com%2Flogin%2Fcallback%3Ffollowup%3Dhttp%253A%252F%252Fwww.mi.com%252Findex.html%26sign%3DNDRhYjQwYmNlZTg2ZGJhZjI0MTJjY2ZiMTNiZWExODMwYjkwNzg2ZQ%2C%2C&sid=mi_eshop\r\n";
- cstrSendData += "Content-Length: " + cstrSendParamLen +"\r\n";
- cstrSendData += "Connection: keep-alive\r\n";
- cstrSendData += "\r\n";
- cstrSendData += cstrSendParam;
- CString cstrRecvData;
- do
- {
- int nRet = SSL_write(ssl, cstrSendData, cstrSendData.GetLength());
- if(-1 == nRet)
- {
- break;
- }
- bRet = TRUE;
- } while (FALSE);
- return bRet;
- }
- void HttpsClient::RecvLoginPostData(CString &cstrRecvData)
- {
- BOOL bRet = FALSE;
- do
- {
- TIMEVAL tval;
- tval.tv_sec = 20;
- tval.tv_usec = 0;
- while(TRUE)
- {
- FD_SET fds;
- FD_ZERO(&fds);
- FD_SET(socketClient, &fds);
- char recvData[1000] = {0};
- int nRecvLen;
- //int nSelect = select(FD_SETSIZE, &fds, NULL, NULL, &tval);
- //if (1 != nSelect)
- //{
- // break;
- //}
- int nErr = SSL_read(ssl, recvData, sizeof(recvData));
- if (nErr <= 0)
- {
- break;
- }
- cstrRecvData += recvData;
- }
- if (cstrRecvData.GetLength() == 0)
- {
- break;
- }
- bRet = TRUE;
- } while (FALSE);
- }
- void HttpsClient::ParseCookieFromRecvData(const CString cstrRecvData)
- {
- list<CString> lstCookiesLine; //!存放Set-Cookie的一行,例:Set-Cookie: vso_uname=houqd_1111;
- CString cstrFind = "Set-Cookie:"; //!查找标记
- CString cstrSeperator = "\r\n"; //!以"\r\n"分割号来分割字符串
- int nPos = 0;
- int nStart = cstrRecvData.Find(cstrSeperator);
- while(nStart != -1)
- {
- CString cstrSessionLine = cstrRecvData.Mid(nPos, nStart - nPos + 1);
- if (cstrSessionLine.Find(cstrFind) != -1)
- {
- CString cstrRealRecord = cstrSessionLine.Right(cstrSessionLine.GetLength() - cstrFind.GetLength() - 3);
- list<CString>::iterator it = find(lstCookiesLine.begin(), lstCookiesLine.end(), cstrRealRecord);
- if (it == lstCookiesLine.end())
- {
- lstCookiesLine.push_back(cstrRealRecord);
- }
- }
- nPos = nStart;
- nStart = cstrRecvData.Find(cstrSeperator, nPos + 2);
- }
- //!根据每行获取的cookie值,解析为key-value的形式
- vector<CString> vecCookieSet;
- for (list<CString>::iterator it = lstCookiesLine.begin(); it != lstCookiesLine.end(); it++)
- {
- CString cstrCookies = *it;
- CString cstrSeperator = ";";
- StaticUtility::StringSplit(cstrCookies, cstrSeperator, vecCookieSet);
- }
- vector<CString> vecTemp;
- for (vector<CString>::iterator it = vecCookieSet.begin(); it != vecCookieSet.end(); it++)
- {
- vecTemp.clear();
- CString cstrOneCookies = *it;
- CString cstrSeperator = "=";
- StaticUtility::StringSplit(cstrOneCookies, cstrSeperator, vecTemp);
- CString cstrKey;
- CString cstrVal;
- if (vecTemp.size() == 2)
- {
- cstrKey = vecTemp[0];
- cstrVal = vecTemp[1];
- }
- if(cstrKey.Compare("userId") == 0)
- {
- cstrCookieUid = cstrVal;
- break;
- }
- }
- }
同理,判断登录也是在返回的信息中拿cookie信息,再进行下一步操作。
四、参考资料及代码下载链接
1) 使用OpenSSL API进行安全编程:http://www.ibm.com/developerworks/cn/linux/l-openssl.html
2) SSL建立过程分析:http://blog.chinaunix.net/uid-127037-id-2919489.html
3) Openssl使用:http://www.cppblog.com/woomsg/archive/2008/11/03/64508.html
4) 知乎OpenSSL:http://www.zhihu.com/topic/19584279
5) Retrieving a file via HTTP:http://www.codeproject.com/Articles/1876/Retrieving-a-file-via-HTTP
6) Step in a Typical HTTP Client Application:https://msdn.microsoft.com/en-us/library/8yh4zs9e%28v=VS.80%29.aspx
7) Make a POST HTTP request over a socket:http://paul.grozav.info/2013/05/16/c-make-a-post-http-request-over-a-socket/
8) C++ STL中哈希表hash_map介绍:blog.csdn.NET/ddkxddkx/article/details/6555754
9) 我的代码实现的下载链接为:http://download.csdn.net/detail/houqingdong2012/8540317
C++模拟Http/Https访问web站点的更多相关文章
- java 网络API访问 web 站点
package cn.magicdu.think.socket; import java.io.BufferedReader; import java.io.InputStreamReader; im ...
- Nginx实战之让用户通过用户名密码认证访问web站点
1.Nginx实战之让用户通过用户名密码认证访问web站点 [root@master ~]# vim /usr/local/nginx/conf/extra/www.conf server { lis ...
- 启动Nginx目录浏览功能及 让用户通过用户名密码认证访问web站点
一.启动Nginx目录浏览功能 [root@abcdocker extra]# cat w.conf server { listen 80; server_name IP地址; location / ...
- apache配置,禁止ip访问web站点
由于一台服务器上面部署了好几个应用,对应不同的域名,如果用户知道ip地址的话,直接用户ip地址访问,会显示第一个虚拟主机的页面(更改了虚拟主机的顺序,每次都是显示第一个).这样对用户造成不好的印象,所 ...
- Nginx之让用户通过用户名密码认证访问web站点
有时我们会有这么一种需求,就是你的网站并不想提供一个公共的访问或者某些页面不希望公开,我们希望的是某些特定的客户端可以访问. 那么我们可以在访问时要求进行身份认证,就如给你自己的家门加一把锁,以拒绝那 ...
- 实战:Nginx如何让用户通过用户名和密码认证访问WEB站点
有时我们会有这么一种需求,就是你的网站并不想提供一个公共的访问或者某些页面不希望公开,我们希望的是某些特定的客户端可以访问.那么我们可以在访问时要求进行身份认证,就如给你自己的家门加一把锁,以拒绝那些 ...
- 浏览器访问web站点原理图
启动tomcat,在浏览器中输入http://localhost:8080/web_kevin/hello.html,发生的事情如下: 1.浏览器解析主机名,即解析localhost.浏览器首先会到本 ...
- web站点启用https (二)
接上篇内容 二.实际配置案例 实验案例:为web站点启用https 实验环境:seven公司有一个web站点,域名为www.seven.com,启用的身份验证方式是基本验证方式.随着业务发展想成为网上 ...
- DNS服务——智能域名解析、镜像Web站点、直接域名泛域名
智能域名解析 智能域名解析只有Linux DNS服务器才有.下面给出2种智能域名解析应用场景. 应用场景1 整个互联网由众多ISP组成,在中国就是联通.电信.移动等等 各家ISP内部网络四通八达,速度 ...
随机推荐
- Unity-Animator(Mecanim)深入系列总索引
花了不少时间完成了这篇Unity Animator学习系列文章,其中大多数内容都来自个人实践,包括API部分很多都是亲测,期望和网上的诸多教程达到互补. 相关参考文档 Unity Animator官方 ...
- catch(…) vs catch(CException *)?
转自:https://stackoverflow.com/questions/7412185/what-is-the-difference-between-catch-vs-catchcexcepti ...
- JS怎样捕获浏览器关闭时间弹出自定义对话框
<script type="text/javascript">window.onbeforeunload = function (e) { e = e || windo ...
- 对于jsp中编码的理解
1.会话都是从客户端也就是浏览器开始发起的,首先用户将地址输入到地址栏中, 当用户输入enter或者点击转到的按钮时,浏览器会根据当前页面的charset对地址栏中的地址进行encode一次,当服务器 ...
- CSS3 transform 引起z-index失效
https://my.oschina.net/u/2941696/blog/1529373
- C语言分支结构之if else语句
前面我们看到的代码都是顺序执行的,也就是先执行第一条语句,然后是第二条.第三条……一直到最后一条语句,这称为顺序结构. 但是对于很多情况,顺序结构的代码是远远不够的,比如一个程序限制了只能成年人使用, ...
- Sphinx以及coreseek的安装及使用 .No1
检索结构php -> sphinx -> mysql非结构化数据又叫全文数据,非固定长度字段例如文章标题搜索这类适用sphinx 全文数据搜索:顺序扫描 : 如like查找索引扫描 : 把 ...
- iPad UIPopoverController弹出窗口的位置和坐标
本文转载至:http://blog.csdn.net/chang6520/article/details/7921181 TodoViewController *contentViewControll ...
- 《C++ Primer Plus》14.2 私有继承 学习笔记
C++(除了成员变量之外)还有另一种实现has-a关系的途径——私有继承.使用私有继承,基类的公有成员和保护成员都将成为派生类的私有成员.(如果使用保护继承,基类的公有成员和保护成员都将称为派生类的保 ...
- ubuntu安装TexturePicker
TexturePacker网页:https://www.codeandweb.com/texturepackerTexturePacker下载页面:https://www.codeandweb.com ...