从零实现HTTP服务器——Minihttpd(二)

上一篇中我们实现了接受浏览器的请求,并返回本地的网页给浏览器展示,接下来对该简单的功能进行下一步完善

Content-Type

http响应头中非常重要的一个字段是Content-Type,它决定了浏览器如何解析返回的响应内容,如果该字段缺失则默认为text/html格式,因此我们上文返回的简单html网页并没有添加该字段,浏览器也能正常解析。
但是稍微复杂的前端页面都包含了css样式文件,JavaScript脚本文件等,如果不指定Content-Type字段,则浏览器无法正确解析这些文件(有些浏览器超强的兼容性可以一定程度上自动判断内容格式)
因此我们在返回本地的文件作为响应时,需要手动设置Content-Type字段,判断依据为文件的扩展名,这里使用了一个map维护扩展名与Content-Type映射关系。

void HttpResponse::init_content_type_map(){
    content_type_map.insert(pair("html","text/html"));
    content_type_map.insert(pair("htm","text/html"));
    content_type_map.insert(pair("shtml","text/html"));
    content_type_map.insert(pair("css","text/css"));
    content_type_map.insert(pair("js","text/javascript"));
    content_type_map.insert(pair("txt","text/plain"));
    content_type_map.insert(pair("js","text/javascript"));
    content_type_map.insert(pair("xml","text/xml"));

    content_type_map.insert(pair("ico","image/x-icon"));
    content_type_map.insert(pair("jpg","image/jpeg"));
    content_type_map.insert(pair("jpeg","image/jpeg"));
    content_type_map.insert(pair("jpe","image/jpeg"));
    content_type_map.insert(pair("gif","image/gif"));
    content_type_map.insert(pair("png","image/png"));
    content_type_map.insert(pair("tiff","image/tiff"));
    content_type_map.insert(pair("tif","image/tiff"));
    content_type_map.insert(pair("rgb","image/x-rgb"));

    content_type_map.insert(pair("mpeg","video/mpeg"));
    content_type_map.insert(pair("mpg","video/mpeg"));
    content_type_map.insert(pair("mpe","video/mpeg"));
    content_type_map.insert(pair("qt","video/quicktime"));
    content_type_map.insert(pair("mov","video/quicktime"));
    content_type_map.insert(pair("avi","video/x-msvideo"));
    content_type_map.insert(pair("movie","video/x-sgi-movie"));

    content_type_map.insert(pair("woff","application/font-woff"));
    content_type_map.insert(pair("ttf","application/octet-stream"));
}

这里添加了一些常用格式的Content-Type类型,后续涉及到更复杂的文件类型时对其进一步扩展

gzip压缩

在http响应的结构中,我们常常可以看到一个名为Content-Encoding的字段,其值大多为gzip,deflate等。该字段决定的是http响应体的编码格式。目前主流浏览器均支持gzip等格式的压缩格式。使用压缩格式的最大好处就是减少网络传输的信息量,提高网页加载速度,但由于服务端多了压缩的步骤,也一定程度增加了服务器的负担(客户端单次处理时,解压的影响可以忽略不计)。
而gzip格式又是应用最广泛的一种压缩格式,其对文本内容的压缩率常常可以达到40%以上,对于html,css,javascript文件均有着非常好的压缩效果。

本文实现的Minihttpd为了增加gzip格式的压缩功能使用了zlib库,其代码均为c编写,使用方法相对简单,这里列出部分供参考

//raw_data为原始数据,buffer为压缩后数据存储缓冲区,buffer_size为缓冲区大小,返回值为压缩后数据字节数
uLong gzip_compress(string raw_data,Bytef*& buffer,int buffer_size){
    size_t raw_data_size = raw_data.size();
    z_stream strm;
    z_stream d_stream;
    d_stream.zalloc = NULL;
    d_stream.zfree = NULL;
    d_stream.opaque = NULL;
    d_stream.next_in = (Bytef*)raw_data.c_str();
    d_stream.avail_in = raw_data_size;
    d_stream.next_out = buffer;
    d_stream.avail_out = buffer_size;

    int ret = deflateInit2(&d_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
                        MAX_WBITS + 16, 8, Z_DEFAULT_STRATEGY);
    if (Z_OK != ret)
    {
        Log::log("init deflate error",ERROR);
        // cout<< ret < 3){
            stringstream ss;
            ss<< "deflate failed,errNo = "<

主要工作流程为:

  1. deflateInit2() 设置压缩格式等信息
  2. deflate() 进行压缩
  3. deflateEnd() 压缩完毕释放临时空间等收尾工作

编码格式判别

接收到http请求后,首先判断请求头中是否包含Accept-Encoding字段,如果存在,检查其后面接受的压缩格式等,决定是否使用gzip压缩(注意响应头也需要添加Content-Encoding:gzip字段)

Github

https://github.com/njuwuyuxin/MiniHttpd
欢迎共同学习

你可能感兴趣的:(从零实现HTTP服务器——Minihttpd(二))