HTTP文件上传
先制作一个简单的html页面,只包含了一个form
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> test upload </head> <body> <form method="post" name="submit" enctype="multipart/form-data"> <input type="file" name="fileField"><br /><br /> <input type="submit" name="submit" value="Submit"> </form> </body> </html>
这里为了文件上传,必须指定multipart/form-data,也就是要求不要编码。
默认的enctype值是application/x-www-form-urlencoded,会对字符进行编码。
具体参考文档:http://www.w3school.com.cn/tags/att_form_enctype.asp
MIME
因为已经涉及到MIME,这里顺便介绍一下。全称是Multipurpose Internet Mail Extensions.
这个对mail的扩展协议允许mail message能够支持非ASCII字符,二进制格式附件等多种格式。
它的写法格式是:
Content-Type: [type]/[subtype]; parameter比如multipart是 type, form-data是 subtype。
具体请参考:http://zh.wikipedia.org/wiki/MIME
HTTP协议有时候也会使用MIME,但并不完全遵循MIME。
CppCMS示例
这个程序很简单,upload 一个pdf文件,然后保存到文件系统。我没有使用CppCMS的Form类,因为那是用C++类渲染HTML Form以及里面的html tags。就像JSF一样,会把事情搞复杂。我并不欣赏这种设计。因此我用的是CppCMS的最基本的方法,从request里获取上传的文件对象,然后保存到磁盘上。因此我的例子比CppCMS的example更好理解。
首先创建CMake工程,目录结构如下:
chenshu@chenshu-beijing:~/work/research/upload$ tree . ├── CMakeLists.txt ├── config.js ├── include │ ├── controller │ │ └── upload_site.h │ └── model │ └── content.h ├── src │ ├── CMakeLists.txt │ ├── controller │ │ └── upload_site.cpp │ ├── main.cpp │ └── view │ └── upload.cpp └── template └── upload.tmpl 7 directories, 9 files
1.负责调用渲染引擎,生成并返回网页
2.将不同的HTTP URL映射到不同的函数
template目录存放了要渲染的网页模板文件。
view目录存放了CppCMS解析模板文件生成的C++类
model存放了渲染网页时需要的数据
现在看一下config.js,配置很简单:
{ "service" : { "ip":"0.0.0.0", "api" : "http", "port" : 8081 }, "http" : { "script_names" : ["/cppcms"] } }
<% c++ #include "model/content.h" %> <% skin upload %> <% view upload_view uses content::upload_content %> <% template render() %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> test upload </head> <body> <form method="post" action="./process_uploaded_file" name="submit" enctype="multipart/form-data"> <input type="file" name="fileField"><br /><br /> <input type="submit" name="submit" value="Submit"> </form> </body> </html> <% end template %> <% end view %> <% end skin %>
#ifndef CONTENT_H #define CONTENT_H #include <cppcms/view.h> namespace content { struct upload_content : public cppcms::base_content { }; } #endif
upload_site.h
#include <cppcms/application.h> #include <cppcms/applications_pool.h> #include <cppcms/service.h> class upload_site : public cppcms::application { public: upload_site(cppcms::service &srv); void upload_page(); void process_uploaded_file(); };
#include "controller/upload_site.h" #include <cppcms/url_dispatcher.h> #include "model/content.h" #include <cppcms/http_file.h> using namespace std; upload_site::upload_site(cppcms::service &srv):cppcms::application(srv) { //web page dispatcher().assign("/upload" , &upload_site::upload_page, this); dispatcher().assign("/process_uploaded_file" , &upload_site::process_uploaded_file, this); } void upload_site::upload_page() { content::upload_content content; render("upload","upload_view", content); } void upload_site::process_uploaded_file() { if(request().request_method()=="POST") { cppcms::http::request::files_type files = request().files(); int size = files.size(); booster::shared_ptr<cppcms::http::file> file = files.at(0); string file_name = file->filename(); file->save_to("/home/chenshu/"+file_name); } }
cmake_minimum_required(VERSION 2.8) set(CMAKE_BUILD_TYPE Debug) set(TEMPLATE_DIR ${CMAKE_SOURCE_DIR}/template) set(VIEW_DIR ${CMAKE_SOURCE_DIR}/src/view) find_package (Threads) find_package(Boost COMPONENTS system filesystem REQUIRED) include_directories(${CMAKE_SOURCE_DIR}/include) add_definitions(-Wall) add_custom_command( OUTPUT ${VIEW_DIR}/upload.cpp COMMAND cppcms_tmpl_cc ${TEMPLATE_DIR}/upload.tmpl -o ${VIEW_DIR}/upload.cpp DEPENDS ${TEMPLATE_DIR}/upload.tmpl ) AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/src CPP_LIST1) set(CPP_LIST2 ${VIEW_DIR}/upload.cpp ) AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/src/controller CPP_LIST3) add_executable(upload ${CPP_LIST1} ${CPP_LIST2} ${CPP_LIST3}) target_link_libraries(upload ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} cppcms booster)
然后upload一个pdf文件。到/home/chenshu/下寻找这个pdf文件。
我用md5sum对比了源文件和网站保存的文件,md5相同。
成功。