<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></title> 
<link>http://jackxiang.com/index.php</link> 
<description><![CDATA[赢在IT，Playin' with IT,Focus on Killer Application,Marketing Meets Technology.]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></copyright>
<item>
<link>http://jackxiang.com/post//</link>
<title><![CDATA[使用Nginx Upload Module及pycurl来实现大文件断点上传 ]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Web服务器]]></category>
<pubDate>Wed, 17 Apr 2013 06:10:53 +0000</pubDate> 
<guid>http://jackxiang.com/post//</guid> 
<description>
<![CDATA[ 
	背景：<br/>&nbsp;&nbsp; 对于Nginx的上传模块，在内存上可能会有不少的缩减和PHP的相比，在性能上也就是上传的速度可能要快2，3倍，但这个模块对认证的配置没有，也就是如有某cookie才能上传等，它仅仅就是一个模块，也就是说这一块还有待hack或作者本人去实现，我看网上也有其它兄弟想用并去试着实现这一块。因为是http里的rfc协议的支持，它也就支持断点续传了，这有一篇文章讲述到这一块，于是做出转载之举动，文章如下：<br/><br/><br/>由于项目需要，需要实现超大文件的上传，且要考虑上传请求的负载均衡、客户端往服务器的断点续传（上行）、服务器可扩展性等需求。对比ftp、自定 义Socket协议、php等服务器脚本实现上传功能后，选择了基于Ngnix Upload Module+pycurl来实现大文件的上传。<br/> <br/>1、 nginx、nginx upload module、nginx upload progress module安装<br/>mkdir ~/nginx-source<br/>cd ~/nginx-source<br/>wget http://nginx.org/download/nginx-1.2.7.tar.gz<br/>tar zxvf nginx-1.2.7.tar.gz<br/>wget http://www.grid.net.ru/nginx/download/nginx_upload_module-2.2.0.tar.gz<br/>tar zxvf nginx_upload_module-2.2.0.tar.gz<br/>wget -O nginx-upload-progress-module-master.zip https://github.com/masterzen/nginx-upload-progress-module/archive/master.zip<br/>unzip nginx-upload-progress-module-master.zip<br/>cd nginx-1.2.7<br/>./configure –user=daemon –group=daemon –prefix=/usr/local/nginx-1.2.7/ –add-module=../nginx_upload_module-2.2.0 –add-module=../nginx-upload-progress-module-master –with-http_stub_status_module –with-http_ssl_module –with-http_sub_module –with-md5=/usr/lib –with-sha1=/usr/lib –with-http_gzip_static_module<br/>make<br/>make install<br/>2、 php安装<br/>mkdir ~/php-source<br/>cd ~/php-source<br/>wget http://www.php.net/get/php-5.4.13.tar.gz/from/cn2.php.net/mirror<br/>tar zxvf php-5.4.13.tar.gz<br/>./configure –prefix=/usr/local –with-config-file-path=/etc –enable-suhosin –enable-fpm –enable-fastcgi –enable-force-cgi-redirect –disable-rpath –enable-discard-path –with-mysql –with-mysqli –with-sqlite –with-pdo-sqlite –with-iconv-dir=/usr/local –with-freetype-dir –with-jpeg-dir –with-png-dir –with-gd –with-zlib –with-libxml-dir –with-curl –with-curlwrappers –with-openssl –with-mhash –with-xmlrpc –with-mcrypt –with-ldap –with-ldap-sasl –enable-xml –enable-safe-mode –enable-bcmath –enable-shmop –enable-sysvsem –enable-inline-optimization –enable-mbregex –enable-mbstring –enable-gd-native-ttf –enable-ftp –with-bz2 –enable-pcntl –enable-sockets –enable-zip –enable-soap –enable-pdo –disable-debug –disable-ipv6<br/>3、 nginx配置<br/>user daemon;<br/>worker_processes 1;<br/>#error_log logs/error.log;<br/>#error_log logs/error.log notice;<br/>#error_log logs/error.log info;<br/>#pid logs/nginx.pid;<br/>events &#123;<br/>worker_connections 1024;<br/>&#125;<br/>http &#123;<br/>include mime.types;<br/>default_type application/octet-stream;<br/>#log_format main ‘$remote_addr – $remote_user [$time_local] “$request” ‘<br/># ‘$status $body_bytes_sent “$http_referer” ‘<br/># ‘”$http_user_agent” “$http_x_forwarded_for”‘;<br/>#access_log logs/access.log main;<br/>sendfile on;<br/>#tcp_nopush on;<br/>#keepalive_timeout 0;<br/>keepalive_timeout 65;<br/>#gzip on;<br/>upstream web&#123;<br/>server 127.0.0.1:80;<br/>&#125;<br/>upstream php&#123;<br/>server 127.0.0.1:9000 max_fails=0;<br/>&#125;<br/>server &#123;<br/>listen 80;<br/>server_name localhost;<br/>#charset koi8-r;<br/>#access_log logs/host.access.log main;<br/>client_max_body_size 100m;<br/># Upload form should be submitted to this location<br/>location /upload &#123;<br/># Pass altered request body to this location<br/>root html;<br/>upload_pass /upload.php;<br/># Store files to this directory<br/># The directory is hashed, subdirectories 0 1 2 3 4 5 6 7 8 9 should exist<br/>upload_store /var/uploads 1;<br/># Allow uploaded files to be read only by user<br/>upload_store_access user:r;<br/>upload_resumable on;<br/># Set specified fields in request body<br/>upload_set_form_field “$&#123;upload_field_name&#125;_name” $upload_file_name;<br/>upload_set_form_field “$&#123;upload_field_name&#125;_content_type” $upload_content_type;<br/>upload_set_form_field “$&#123;upload_field_name&#125;_path” $upload_tmp_path;<br/># Inform backend about hash and size of a file<br/>upload_aggregate_form_field “$&#123;upload_field_name&#125;_md5″ $upload_file_md5;<br/>upload_aggregate_form_field “$&#123;upload_field_name&#125;_size” $upload_file_size;<br/>upload_pass_form_field “^submit$&#124;^description$”;<br/>&#125;<br/>#error_page 404 /404.html;<br/>error_page 405 =200 @405;<br/>location @405<br/>&#123;<br/>root html;<br/>&#125;<br/># redirect server error pages to the static page /50x.html<br/>#<br/>error_page 500 502 503 504 /50x.html;<br/>location = /50x.html &#123;<br/>root html;<br/>&#125;<br/># pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000<br/>#<br/>#location ~ &#92;.php$ &#123;<br/>location ~ .*&#92;.php(&#92;/.*)*$ &#123;<br/>root html;<br/>fastcgi_pass 127.0.0.1:9000;<br/>fastcgi_index index.php;<br/>fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;<br/>include fastcgi_params;<br/>&#125;<br/>&#125;<br/>&#125;<br/>创建上传目录<br/>mkdir -p /var/uploads/&#123;0..9&#125;<br/>mkdir -p /var/uploads/&#123;a..z&#125;<br/>chown -R daemon:daemon /var/uploads<br/>启动<br/>/usr/local/nginx-1.2.7/sbin/nginx<br/>/usr/local/sbin/php-fpm<br/>4、 在document root 目录html下创建upload.html和upload.php<br/>upload.html<br/>Select files to upload<br/><br/> <br/>upload.php<br/> <br/>5、 测试<br/>页面上传测试：<br/>http://127.0.0.1/upload.html<br/>使用curl测试文件上传：<br/>curl -v -i -XPOST http://127.0.0.1/upload -F “media=@/home/liangchuan/baby4.jpg;type=image/jpeg;filename=baby4.jpg<br/>使用pycurl脚本测试大文件分段续传（测试了一个90M的文件，每块按照30M传输）：<br/># -*- coding: utf-8 -*-<br/>import pycurl<br/>import StringIO<br/>import os<br/>import math<br/>chunksize=30000000<br/>filename=’/home/liangchuan/test.rar’<br/>class FileReader:<br/>def __init__(self, fp, start, length):<br/>self.fp = fp<br/>self.fp.seek(start)<br/>self.length = length<br/>def read_callback(self, size):<br/>#print ‘read_callback(%d)’ % size<br/>if self.length == 0: # read all<br/>return ”<br/>if self.length &gt; size:<br/>self.length -= size<br/>#print ‘set size = %d’ % size<br/>return self.fp.read(size)<br/>else :<br/>size = self.length<br/>self.length -= size<br/>return self.fp.read(size)<br/>fout = StringIO.StringIO()<br/>filesize = os.path.getsize(filename)<br/>c = pycurl.Curl()<br/>c.setopt(c.URL, ‘http://127.0.0.1/upload’)<br/>pf = [(&#039;test&#039;, (c.FORM_FILE, filename,c.FORM_CONTENTTYPE,&#039;application/x-rar-compressed&#039;)) ]<br/>c.setopt(c.HTTPPOST, pf)<br/>c.setopt(c.VERBOSE, 1)<br/>num=int(filesize/chunksize)+1<br/>import StringIO<br/>b = StringIO.StringIO()<br/>c.setopt(pycurl.WRITEFUNCTION, b.write)<br/>for i in range(1,num):<br/>c.setopt(pycurl.INFILESIZE, chunksize)<br/>c.setopt(pycurl.READFUNCTION, FileReader(open(filename, ‘rb’), (i-1)*chunksize,chunksize).read_callback)<br/>c.setopt(pycurl.RANGE,’%s-%s’ % ((i-1)*chunksize,i*chunksize))<br/>c.perform()<br/>print b.getvalue()<br/>#response_code = c.getinfo(pycurl.RESPONSE_CODE)<br/>#response_data = fout.getvalue()<br/>#print response_code<br/>#print response_data<br/>c.close()<br/>备注：<br/>1、 上述脚本只是用于测试使用，用于实际的生产场合（例如用于大文件的自动断点传输），在机制上还有需要完善的。大的思路：<br/>服务器端的upload.php通过Redis或数据库等其他机制来存储每块文件上传的状态，并提供查询接口供客户端查询<br/>客户端使用sqlite来维护每块文件的传输状态，失败后，先调用服务器的查询接口查询成功的range值，然后从指定的range值重新发起上传操作<br/>2、 以上pycurl的例子主要是测试后台自动上传功能，如果是基于有Web界面的文件上传，可以参考http://blueimp.github.com/jQuery-File-Upload/<br/><br/>来自：http://blog.sina.com.cn/s/blog_5921b17e01019oil.html
]]>
</description>
</item><item>
<link>http://jackxiang.com/post//#blogcomment</link>
<title><![CDATA[[评论] 使用Nginx Upload Module及pycurl来实现大文件断点上传 ]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>http://jackxiang.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>