然而,即使在没有设置特殊含义的状态代码时,指定应答头也是很有用的。应答头可以用来完成:设置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] = ' '; if (!trunc_head) { if ((body_ptr = strstr(resp->body, " ")) != NULL) { *(body_ptr+2) = ' '; 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] = ' '; 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; }