博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
mochiweb 源码阅读(二十)
阅读量:7135 次
发布时间:2019-06-28

本文共 7223 字,大约阅读时间需要 24 分钟。

  大家好,今天继续上一篇没讲完的mochiweb_request:not_found/1函数:

%% @spec not_found(ExtraHeaders) -> response()%% @doc Alias for respond({404, [{"Content-Type", "text/plain"}%% | ExtraHeaders], <<"Not found.">>}).not_found(ExtraHeaders) ->    respond({
404, [{"Content-Type", "text/plain"} | ExtraHeaders], <<"Not found.">>}).

  这个函数就一行代码,调用mochiweb_request:respond/1函数返回404错误,关于这个函数,我们之后还有讲到,到时候再详细看吧。

  回到mochiweb_request:serve_file/3函数,我们看看剩余部分代码:

RelPath ->            FullPath = filename:join([DocRoot, RelPath]),            case filelib:is_dir(FullPath) of                true ->                    maybe_redirect(RelPath, FullPath, ExtraHeaders);                false ->                    maybe_serve_file(FullPath, ExtraHeaders)            end

  这里根据mochiweb_util:safe_relative_path/1返回的真实路径RelPath以及DocRoot组合成新的路径:FullPath = filename:join([DocRoot, RelPath]),接着调用函数:filelib:is_dir/1函数,这个函数的erlang doc 地址:,如下图:  

  如果Name指的是目录,则该函数返回true,否则返回false。

  如果为true,则调用mochiweb_request:maybe_redirect/3函数;如果为false,则调用mochiweb_request:maybe_serve_file/2函数

  那么我们先来看下第一个函数:

maybe_redirect([], FullPath, ExtraHeaders) ->    maybe_serve_file(directory_index(FullPath), ExtraHeaders);maybe_redirect(RelPath, FullPath, ExtraHeaders) ->    case string:right(RelPath, 1) of        "/" ->            maybe_serve_file(directory_index(FullPath), ExtraHeaders);        _   ->            Host = mochiweb_headers:get_value("host", Headers),            Location = "http://" ++ Host  ++ "/" ++ RelPath ++ "/",            LocationBin = list_to_binary(Location),            MoreHeaders = [{"Location", Location},                           {
"Content-Type", "text/html"} | ExtraHeaders], Top = <<"" "" "301 Moved Permanently" "" "

Moved Permanently

" "

The document has moved >, Bottom = <<">here.

\n">>, Body = <
>, respond({
301, MoreHeaders, Body}) end.

  如果RelPath为[],则调用第一个分支:

maybe_redirect([], FullPath, ExtraHeaders) ->    maybe_serve_file(directory_index(FullPath), ExtraHeaders);

  这里先调用mochiweb_request:directory_index/1函数:

%% This has the same effect as the DirectoryIndex directive in httpddirectory_index(FullPath) ->    filename:join([FullPath, "index.html"]).

  这个函数就一行代码,调用:filename:join/1拼出目录首页地址,继续回到mochiweb_request:maybe_redirect/3函数第一个分支,看下调用mochiweb_request:maybe_serve_file/2函数

maybe_serve_file(File, ExtraHeaders) ->    case file:read_file_info(File) of        {ok, FileInfo} ->            LastModified = httpd_util:rfc1123_date(FileInfo#file_info.mtime),            case get_header_value("if-modified-since") of                LastModified ->                    respond({
304, ExtraHeaders, ""}); _ -> case file:open(File, [raw, binary]) of {ok, IoDevice} -> ContentType = mochiweb_util:guess_mime(File), Res = ok({ContentType, [{
"last-modified", LastModified} | ExtraHeaders], {file, IoDevice}}), ok = file:close(IoDevice), Res; _ -> not_found(ExtraHeaders) end end; {error, _} -> not_found(ExtraHeaders) end.

  这个函数,首先调用file:read_file_info/1函数,erlang doc 地址:,如下图:

  大致翻译:

  检索文件信息,如果成功,返回{ok, FileInfo},否则返回{error, Reason}FileInfo是一个file_info记录,在Kernel包含的文件file.hrl中定义。包括下列指令模块调用调用该函数:-include_lib("kernel/include/file.hrl").

  记录定义如下:

-record(file_info,    {size   :: non_neg_integer(),    % Size of file in bytes.     type   :: 'device' | 'directory' | 'other' | 'regular' | 'symlink',     access :: 'read' | 'write' | 'read_write' | 'none',     atime  :: file:date_time() | integer(), % The local time the file was last read:                             % {
{Year, Mon, Day}, {Hour, Min, Sec}}. % atime, ctime, mtime may also be unix epochs() mtime :: file:date_time() | integer(), % The local time the file was last written. ctime :: file:date_time() | integer(), % The interpretation of this time field % is dependent on operating system. % On Unix it is the last time the file % or the inode was changed. On Windows, % it is the creation time. mode :: integer(), % File permissions. On Windows, % the owner permissions will be % duplicated for group and user. links :: non_neg_integer(), % Number of links to the file (1 if the % filesystem doesn't support links). major_device :: integer(), % Identifies the file system (Unix), % or the drive number (A: = 0, B: = 1) % (Windows). %% The following are Unix specific. %% They are set to zero on other operating systems. minor_device :: integer(), % Only valid for devices. inode :: integer(), % Inode number for file. uid :: integer(), % User id for owner. gid :: integer()}). % Group id for owner.

  从上面看,定义的字段还是比较多的,我就不一一说了,大家参照erlang doc 文档理解下。

  继续回到mochiweb_request:maybe_serve_file/2函数,如果正确返回:{ok, FileInfo},则继续正确处理逻辑;如果返回:{error, _},则调用:mochiweb_request:not_found/1函数。

  首先:LastModified = httpd_util:rfc1123_date(FileInfo#file_info.mtime),这里根据读取到的文件信息中的最后一次写的时间,来生成一个rfc1123 date,erlang doc 地址:,如下图:

  大致翻译:rfc1123_date/0返回RFC 1123格式的当前日期。rfc1123_date/1把date格式转为RFC 1123日期格式。

  获取到日期以后,接着调用:mochiweb_request:get_header_value/1函数:

%% @spec get_header_value(K) -> undefined | Value%% @doc Get the value of a given request header.get_header_value(K) ->    mochiweb_headers:get_value(K, Headers).

  这个函数就一行逻辑,调用mochiweb_headers:get_value/2函数,并传递需要的头部属性,以及Headers(该字段值为gb_trees类型)来获取指定头部属性的值:

%% @spec get_value(key(), headers()) -> string() | undefined%% @doc Return the value of the given header using a case insensitive search.%%      undefined will be returned for keys that are not present.get_value(K, T) ->    case lookup(K, T) of        {value, {_, V}} ->            expand(V);        none ->            undefined    end.

  这个函数调用:mochiweb_headers:lookup/2函数,读取对应K的值:

%% @spec lookup(key(), headers()) -> {value, {key(), string()}} | none%% @doc Return the case preserved key and value for the given header using%%      a case insensitive search. none will be returned for keys that are%%      not present.lookup(K, T) ->    case gb_trees:lookup(normalize(K), T) of        {value, {K0, V}} ->            {value, {K0, expand(V)}};        none ->            none    end.

  其他相关的函数如下:

  mochiweb_headers:normalize/1函数:

normalize(K) when is_list(K) ->    string:to_lower(K);normalize(K) when is_atom(K) ->    normalize(atom_to_list(K));normalize(K) when is_binary(K) ->    normalize(binary_to_list(K)).

  mochiweb_headers:expand/1函数:

expand({array, L}) ->    mochiweb_util:join(lists:reverse(L), ", ");expand(V) ->    V.

  这两个也很简单,就不一一说了。

  最后,需要大家先了解下:HTTP的请求头标签 If-Modified-Since,这里有博客园朋友写的一篇文章,大家可以看下:,部分内容:

  

  今天就到这里,下一篇再见。

 

转载地址:http://rvvrl.baihongyu.com/

你可能感兴趣的文章
计算机存储器
查看>>
JavaScript是如何工作的:渲染引擎和优化其性能的技巧
查看>>
vue中provide-inject跨多组件通讯
查看>>
【资料合集】2017云栖大会·北京峰会回顾合集:PDF下载
查看>>
087-设置服务器的中文字体
查看>>
数据分析:构建可视化报表服务
查看>>
redis 单实例使用及简单封装
查看>>
企业该如何做大数据的分析挖掘?这里有一份参考指南
查看>>
Execution failed for task ':app:processDebugResources'. No slave process to process jobs, aborting
查看>>
linux基础(day 33)
查看>>
12.6 Nginx安装 12.7 默认虚拟主机 12.8 Nginx用户认证 12.9 Nginx域名重定向
查看>>
MaxCompute Studio 使用入门
查看>>
linux进程介绍
查看>>
nginx服务器出现504 gateway time-out怎么解决
查看>>
Java-实现链表的基本操作
查看>>
Eclipse Platform 4.3.1.M20130814-0800
查看>>
MapReduce函数的JavaScript模拟实现
查看>>
在cs后台获取前台datalist控件里的其他控件
查看>>
100-50
查看>>
eclipse 新增代码补全
查看>>