当前位置: 首页 > 工具软件 > Yaws > 使用案例 >

Yaws(erlang web服务器框架) 学习记录之文件上传

赏梓
2023-12-01

Yaws提供了文件上传的API函数,从一些参考资料或Yaws的示例中,都提及使用yaws_api:parse_multipart_post/1这个API函数在服务器端进行文件数据的接受和处理。而在Yaws官方文档中,却提及了另一个API函数,即yaws_multipart:read_multipart_form/2在服务器端进行上传文件数据的处理。

由于,以前还没有接触过Yaws框架,所以详细阅读了相关资料。要掌握对文件上传的处理,除了掌握以上提到的API函数以外,还需要了解out/1函数在接受文件上传时的工作方法。

一、out/1函数在授受文件上传时的工作方法

1.对于较小的文件,浏览器会一次性将文件数据传送到服务器端,此时,out/1函数仅调用一次就完成了文件数据的接收;out/1函数返回相关的提示信息等即可。

2.对于较大的文件,浏览器会将上传的文件数据分块上传到服务器端,在服务器端进行接受时,要通过多次调用out/1函数来完成数据的接收和处理。此时,out/1函数需要多次返回{get_more,Content,State},表示还有下一块文件数据需要接收。这样,out/1函数会被反复调用,以接收文件数据并处理。直到out/1函数不返回get_more这个元组为止。而多次调用out/1函数时,相应的文件数据处理的状态({get_more,Content,State}中的State)会保存在arg记录中的state域中。

二、运用yaws_multipart:read_multipart_form/2函数解析文件数据,进行数据的保存或处理

yaws_multipart:read_multipart_form/2函数的参数有两个,第一个还是arg,而第二个是对接受文件数据处理的一些选项(用list来保存)。主要的选项有指示文件数据是存储在临时文件中还是存储在内存中,最后一并处理。其标志为no_temp_file这个原子值。

注意:如果文件保存在临时文件中,当临时文件用完后,应删除这个临时文件。

yaws_multipart:read_multipart_form/2函数返回的值有三种:

1.{get_more,Content,State} 与out/1相同,即此时表示文件数据的接收还没有完成,要处理好已接受的数据,并等待下次out/1函数的调用。

2.{done,Adict} 此时,上传的文件数据接收完成,可以对所有的数据时行处理。

3.{error,Reason} 即文件上传出错。

对于第2种情形很容易处理,即返回的Adict是一个dict。此时,调用dict:find/2来查找相应的参数(文件上传的文件域的名称),并处理返回的列表即可。具体的说,返回的列表主要包括:

[{filename, "name of the uploaded file as entered on the form"},
{value, Contents_of_the_file_all_in_memory} | _T]
or:
[{filename, "name of the uploaded file as entered on the form"},
{temp_file, "full pathname of the temp file"} | _T]

这两种形式的列表,第一种形式就是文件数据在内存中即 Contents_of_the_file_all_in_memory变量代表的值。第二种形式表示文件数据在临时文件中,其文件路径为字符串形式。

对于上传大文件的处理,可以使用如下形式的代码:

<erl>
-record(upload, {
          fd,
          filename,
          fixed_filename,
          last = false,
          param_name,
          param_running_value,
          params,
          running_file_size = 0,
          max_file_size,
          no_temp_file,
          temp_dir = yaws:tmpdir("/tmp"),
          temp_file,
          headers = [],
          data_type = list
}).
    out(Arg) ->
        % Options = [{temp_file,"my.txt"},{temp_dir,"./logs"}],
        Options = [no_temp_file],
        Parse =  yaws_multipart:read_multipart_form(Arg, Options),
        case Parse of                                                
            {done, _AllContents} when Arg#arg.state /= undefined -> %可以在此处进行文件数据接收完成后的处理,%此保护式用以区别上传小文件时一次的文件数据传送。
                io:format("all:~p~n",[_AllContents]),
                Upload = Arg#arg.state,
                io:format("filename:~p~n",[Upload#upload.filename]),       %客户端上传的文件名称
                io:format("tempname:~p~n",[Upload#upload.fixed_filename]), %服务器端临时文件路径
                io:format("params:~p~n",[Upload#upload.params]),           %如果上传文件数据是在内存中的,则会放在Upload#upload.params中
                {html,"once ok!"};                                         %返回上传文件成功的提示
            {error, _Reason} -> {html,"error!"};
            {get_more, Contents, State} ->
                io:format("~n~p~n",[Contents]),
                io:format("~n~p~n",[State]),
                {get_more, Contents, State}                              %返回这个值时,表示会多次调用out/1函数来接收文件数据
        end.

</erl>

 类似资料: