Linux企業級專案實踐之網路爬蟲(12)——處理HTTP應答頭
Web伺服器的HTTP應答一般由以下幾項構成:一個狀態行,一個或多個應答頭,一個空行,內容文件。設定HTTP應答頭往往和設定狀態行中的狀態程式碼結合起來。例如,有好幾個表示“文件位置已經改變”的狀態程式碼都伴隨著一個Location頭,而401(Unauthorized)狀態程式碼則必須伴隨一個WWW-Authenticate頭。
然而,即使在沒有設定特殊含義的狀態程式碼時,指定應答頭也是很有用的。應答頭可以用來完成:設定Cookie,指定修改日期,指示瀏覽器按照指定的間隔重新整理頁面,宣告文件的長度以便利用持久HTTP連線,……等等許多其他任務。
設定應答頭最常用的方法是HttpServletResponse的setHeader,該方法有兩個引數,分別表示應答頭的名字和值。和設定狀態程式碼相似,設定應答頭應該在傳送任何文件內容之前進行。
HTTP應答頭 說明:
Allow 伺服器支援哪些請求方法(如GET、POST等)。
Content-Encoding 文件的編碼(Encode)方法。只有在解碼之後才可以得到Content-Type頭指定的內容型別。利用gzip壓縮文件能夠顯著地減少HTML文件的下載時間。Java的GZIPOutputStream可以很方便地進行gzip壓縮,但只有Unix上的Netscape和Windows上的IE 4、IE 5才支援它。因此,Servlet應該通過檢視Accept-Encoding頭(即request.getHeader("Accept-Encoding"))檢查瀏覽器是否支援gzip,為支援gzip的瀏覽器返回經gzip壓縮的HTML頁面,為其他瀏覽器返回普通頁面。
Content-Length 表示內容長度。只有當瀏覽器使用持久HTTP連線時才需要這個資料。如果你想要利用持久連線的優勢,可以把輸出文件寫入ByteArrayOutputStram,完成後檢視其大小,然後把該值放入Content-Length頭,最後通過byteArrayStream.writeTo(response.getOutputStream()傳送內容。
Content-Type 表示後面的文件屬於什麼MIME型別。Servlet預設為text/plain,但通常需要顯式地指定為text/html。由於經常要設定Content-Type,因此HttpServletResponse提供了一個專用的方法setContentType。
Date 當前的GMT時間。你可以用setDateHeader來設定這個頭以避免轉換時間格式的麻煩。
Expires 應該在什麼時候認為文件已經過期,從而不再快取它?
然而,即使在沒有設定特殊含義的狀態程式碼時,指定應答頭也是很有用的。應答頭可以用來完成:設定Cookie,指定修改日期,指示瀏覽器按照指定的間隔重新整理頁面,宣告文件的長度以便利用持久HTTP連線,……等等許多其他任務。
設定應答頭最常用的方法是HttpServletResponse的setHeader,該方法有兩個引數,分別表示應答頭的名字和值。和設定狀態程式碼相似,設定應答頭應該在傳送任何文件內容之前進行。
HTTP應答頭 說明:
Allow 伺服器支援哪些請求方法(如GET、POST等)。
Content-Encoding 文件的編碼(Encode)方法。只有在解碼之後才可以得到Content-Type頭指定的內容型別。利用gzip壓縮文件能夠顯著地減少HTML文件的下載時間。Java的GZIPOutputStream可以很方便地進行gzip壓縮,但只有Unix上的Netscape和Windows上的IE 4、IE 5才支援它。因此,Servlet應該通過檢視Accept-Encoding頭(即request.getHeader("Accept-Encoding"))檢查瀏覽器是否支援gzip,為支援gzip的瀏覽器返回經gzip壓縮的HTML頁面,為其他瀏覽器返回普通頁面。
Content-Length 表示內容長度。只有當瀏覽器使用持久HTTP連線時才需要這個資料。如果你想要利用持久連線的優勢,可以把輸出文件寫入ByteArrayOutputStram,完成後檢視其大小,然後把該值放入Content-Length頭,最後通過byteArrayStream.writeTo(response.getOutputStream()傳送內容。
Content-Type 表示後面的文件屬於什麼MIME型別。Servlet預設為text/plain,但通常需要顯式地指定為text/html。由於經常要設定Content-Type,因此HttpServletResponse提供了一個專用的方法setContentType。
Date 當前的GMT時間。你可以用setDateHeader來設定這個頭以避免轉換時間格式的麻煩。
Expires 應該在什麼時候認為文件已經過期,從而不再快取它?
void * recv_response(void * arg)
{
begin_thread();
int i, n, trunc_head = 0, len = 0;
char * body_ptr = NULL;
evso_arg * narg = (evso_arg *)arg;
Response *resp = (Response *)malloc(sizeof(Response));
resp->header = NULL;
resp->body = (char *)malloc(HTML_MAXLEN);
resp->body_len = 0;
resp->url = narg->url;
regex_t re;
if (regcomp(&re, HREF_PATTERN, 0) != 0) {/* compile error */
SPIDER_LOG(SPIDER_LEVEL_ERROR, "compile regex error");
}
SPIDER_LOG(SPIDER_LEVEL_INFO, "Crawling url: %s/%s", narg->url->domain, narg->url->path);
while(1) {
/* what if content-length exceeds HTML_MAXLEN? */
n = read(narg->fd, resp->body + len, 1024);
if (n < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
/**
* TODO: Why always recv EAGAIN?
* should we deal EINTR
*/
//SPIDER_LOG(SPIDER_LEVEL_WARN, "thread %lu meet EAGAIN or EWOULDBLOCK, sleep", pthread_self());
usleep(100000);
continue;
}
SPIDER_LOG(SPIDER_LEVEL_WARN, "Read socket fail: %s", strerror(errno));
break;
} else if (n == 0) {
/* finish reading */
resp->body_len = len;
if (resp->body_len > 0) {
extract_url(&re, resp->body, narg->url);
}
/* deal resp->body */
for (i = 0; i < (int)modules_post_html.size(); i++) {
modules_post_html[i]->handle(resp);
}
break;
} else {
//SPIDER_LOG(SPIDER_LEVEL_WARN, "read socket ok! len=%d", n);
len += n;
resp->body[len] = '\0';
if (!trunc_head) {
if ((body_ptr = strstr(resp->body, "\r\n\r\n")) != NULL) {
*(body_ptr+2) = '\0';
resp->header = parse_header(resp->body);
if (!header_postcheck(resp->header)) {
goto leave; /* modulues filter fail */
}
trunc_head = 1;
/* cover header */
body_ptr += 4;
for (i = 0; *body_ptr; i++) {
resp->body[i] = *body_ptr;
body_ptr++;
}
resp->body[i] = '\0';
len = i;
}
continue;
}
}
}
leave:
close(narg->fd); /* close socket */
free_url(narg->url); /* free Url object */
regfree(&re); /* free regex object */
/* free resp */
free(resp->header->content_type);
free(resp->header);
free(resp->body);
free(resp);
end_thread();
return NULL;
}
相關文章
- Linux企業級專案實踐之網路爬蟲(11)——處理http請求頭Linux爬蟲HTTP
- Linux企業級專案實踐之網路爬蟲(28)——爬蟲socket處理Linux爬蟲
- Linux企業級專案實踐之網路爬蟲(10)——處理HTTP狀態碼Linux爬蟲HTTP
- Linux企業級專案實踐之網路爬蟲(18)——佇列處理Linux爬蟲佇列
- Linux企業級專案實踐之網路爬蟲(5)——處理配置檔案Linux爬蟲
- Linux企業級專案實踐之網路爬蟲(13)——處理user-agentLinux爬蟲
- Linux企業級專案實踐之網路爬蟲(7)——DNS解析Linux爬蟲DNS
- Linux企業級專案實踐之網路爬蟲(19)——epoll介面Linux爬蟲
- Linux企業級專案實踐之網路爬蟲(4)——主程式流程Linux爬蟲
- Linux企業級專案實踐之網路爬蟲(8)——認識URLLinux爬蟲
- Linux企業級專案實踐之網路爬蟲(25)——管理原始碼之SVNLinux爬蟲原始碼
- Linux企業級專案實踐之網路爬蟲(21)——擴充套件為多工爬蟲Linux爬蟲套件
- Linux企業級專案實踐之網路爬蟲(17)——儲存頁面Linux爬蟲
- Linux企業級專案實踐之網路爬蟲(26)——執行緒池Linux爬蟲執行緒
- Linux企業級專案實踐之網路爬蟲(27)——多路IO複用Linux爬蟲
- Linux企業級專案實踐之網路爬蟲(29)——遵守robots.txtLinux爬蟲
- Linux企業級專案實踐之網路爬蟲(24)——定製規則擴充套件為垂直爬蟲Linux爬蟲套件
- Linux企業級專案實踐之網路爬蟲(9)——通過URL抓取網頁內容Linux爬蟲網頁
- Linux企業級專案實踐之網路爬蟲(22)——編寫爬蟲系統服務控制指令碼Linux爬蟲指令碼
- Linux企業級專案實踐之網路爬蟲(6)——將程式設計成為守護程式Linux爬蟲程式設計
- Linux企業級專案實踐之網路爬蟲(15)——區分文字檔案和二進位制檔案Linux爬蟲
- Linux企業級專案實踐之網路爬蟲(14)——使用正規表示式抽取HTML正文和URLLinux爬蟲HTML
- Linux企業級專案實踐之網路爬蟲(20)——擴充套件成為規則外掛模式Linux爬蟲套件模式
- Linux企業級專案實踐之網路爬蟲(23)——系統測試:找出系統中的bugLinux爬蟲
- Linux企業級專案實踐之網路爬蟲(16)——使用base64傳輸二進位制資料Linux爬蟲
- Linux企業級專案實踐之網路爬蟲(30)——通過查閱RFC文件擴充更加複雜的功能Linux爬蟲
- 網路爬蟲專案爬蟲
- HTTP爬蟲被封如何處理?HTTP爬蟲
- 企業資料爬蟲專案爬蟲
- 網路爬蟲專案蒐集爬蟲
- 企業資料爬蟲專案(二)爬蟲
- Python網路爬蟲實戰專案大全 32個Python爬蟲專案demoPython爬蟲
- 專案--python網路爬蟲Python爬蟲
- 網路爬蟲(python專案)爬蟲Python
- Python網路爬蟲實戰小專案Python爬蟲
- Python網路爬蟲實戰專案大全!Python爬蟲
- Java 爬蟲專案實戰之爬蟲簡介Java爬蟲
- python網路爬蟲應用_python網路爬蟲應用實戰Python爬蟲