我已经设置了一个服务器(好吧......两个服务器,但我认为这个问题不太相关)运行Tornado(版本2.4.1)并由Nginx(版本1.4.4)代理。
我需要通过json
请求定期将POST
(基本上是文本)文件上传到其中一个文件。这些文件将大大受益于gzip压缩(当我手动压缩文件时,压缩率达到90%),但我不知道如何以一种很好的方式给它们充气。
理想情况下,Nginx会对它进行充气并将它整洁地传递给龙卷风......但这不是现在正在发生的事情,因为你可能已经猜到了,否则我不会问这个问题 :-)
这些是我nginx.conf
文件的相关部分(或我认为相关的部分,因为我对Nginx和Tornado很新):
user borrajax;
worker_processes 1;
pid /tmp/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
access_log /tmp/access.log main;
error_log /tmp/error.log;
# Basic Settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
gzip on;
gzip_disable "msie6";
gzip_types application/json text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript image/x-icon image/bmp;
gzip_http_version 1.1;
gzip_proxied expired no-cache no-store private auth;
upstream web {
server 127.0.0.1:8000;
}
upstream input {
server 127.0.0.1:8200;
}
server {
listen 80 default_server;
server_name localhost;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://web;
}
}
server {
listen 81 default_server;
server_name input.localhost;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://input;
}
}
}
正如我之前提到的,有两个Tornado服务器。 main 正在localhost:8000
上运行,用于网页和那种东西。在localhost:8200
上运行的那个是用于接收那些json
文件的那个。这个设置工作正常,除了Gzip部分。
我希望Nginx能够对来自localhost:81
的gzip压缩请求进行充气,并将它们转发给我在localhost:8200
上运行的Tornado(充气)
使用这样的配置,数据到达Tornado,但是主体仍然被压缩,Tornado抛出异常:
[E 140108 15:33:42 input:1085] Uncaught exception POST
/input/log?ts=1389213222 (127.0.0.1)
HTTPRequest(
protocol='http', host='192.168.0.140:81',
method='POST', uri='/input/log?&ts=1389213222',
version='HTTP/1.0', remote_ip='127.0.0.1', body='\x1f\x8b\x08\x00\x00',
headers={'Content-Length': '1325', 'Accept-Encoding': 'deflate, gzip',
'Content-Encoding': 'gzip', 'Host': '192.168.0.140:81', 'Accept': '*/*',
'User-Agent': 'curl/7.23.1 libcurl/7.23.1 OpenSSL/1.0.1c zlib/1.2.7',
'Connection': 'close', 'X-Real-Ip': '192.168.0.94',
'Content-Type': 'application/json'}
)
我知道我总是可以在body
Tornado处理程序中获取请求post()
并手动充气,但这听起来很脏......
最后,这是我用来上传gzip压缩文件的curl
调用:
curl --max-time 60 --silent --location --insecure \
--write-out "%{http_code}" --request POST \
--compressed \
--header "Content-Encoding:gzip" \
--header "Content-Type:application/json" \
--data-binary "$log_file_path.gz" \
"/input/log?ts=1389216192" \
--output /dev/null \
--trace-ascii "/tmp/curl_trace.log" \
--connect-timeout 30
$log_file_path.gz
中的文件是使用gzip $log_file_path
生成的(我的意思是......是常规的Gzip压缩文件)
如果这是通过Nginx无法实现的,那么Tornado中的自动化方法也会起作用(更可靠和优雅让我在POST请求的处理程序中解压缩文件)就像。 ..像Django中间件或类似的东西?
提前谢谢!!
答案 0 :(得分:1)
你已经在某个地方调用了json.loads()
(Tornado没有为你解码json,所以你看到的异常(但没有引用)必须来自你自己的代码);为什么不直接用检查Content-Encoding
和Content-Type
标题并正确解码的方法替换它?
答案 1 :(得分:0)
我放弃了尝试让Nginx或Tornado自动扩展POST请求的主体,所以我选择了Ben Darnell在他的回答中提到的内容。我使用gzip压缩文件并将其作为表单的一部分POST(就像我上传文件一样)。
我会发布一些代码来处理它,以防万一这会帮助其他人:
在客户端(使用curl的bash脚本):
要发送的文件的路径(绝对值)位于变量f
中。变量TMP_DIR
指向/tmp/
,SCRIPT_NAME
包含尝试执行上传的bash脚本的名称(即uploader.sh
)
zip_f_path="$TMP_DIR/$(basename ${f}).gz"
[[ -f "${zip_f_path}" ]] && rm -f "${zip_f_path}" &>/dev/null
gzip -c "$f" 1> "${zip_f_path}"
if [ $? -eq 0 ] && [[ -s "${zip_f_path}" ]]
then
response=$(curl --max-time 60 --silent --location --insecure \
--write-out "%{http_code}" --request POST \
"${url}" \
--output /dev/null \
--trace-ascii "${TMP_DIR}/${SCRIPT_NAME}_trace.log" \
--connect-timeout 30 \
--form "data=@${zip_f_path};type=application/x-gzip")
else
echo "Attempt to compress $f into $zip_f_path failed"
fi
在服务器中(在Tornado处理程序中):
try:
content_type = self.request.files['data'][0]['content_type']
if content_type == 'application/x-gzip':
gzip_decompressor = GzipDecompressor()
file_body = gzip_decompressor.decompress(
self.request.files['data'][0]['body'])
file_body += gzip_decompressor.flush()
else:
file_body = self.request.files['data'][0]['body']
except:
self.send_error(400)
logging.error('Failed to interpret data: %s',
self.request.files['data'])
return