nodejs和php 文件内容传输给php应该用什么格式

其中请求报文中的开始行和首部行包含了常见的各种信息,比如http协议版本,方法(GET/POST),accept-language,cookie等等。 而'实体主体'一般在post中使用,比如我们用表单上传文件,文件数据就是在这个'实体主体'当中。
引子& 写这篇教程的起因是因为在学习nodejs的过程中,想要自己实现一些文件上传的功能,于是不得不去研究POST。
如果你写过一点PHP,那么你肯定记得,在PHP里面,进行文件上传的时候,我们可以直接使用全局变量 $_FILE['name' ]来获取已经被临时存储的文件信息。
但是实际上,POST数据实体,会根据数据量的大小进行分包传送,然后再从这些数据包里面分析出哪些是文件的元数据,那些是文件本身的数据。
PHP是底层做了封装,但是在nodejs里面,这个看似常见的功能却是需要自己来实现的。这篇文章主要就是介绍如何使用nodejs来解析post数据。
正文& 总体上来说,对于post文件上传这样的过程,主要有以下几个部分:
获取http请求报文肿的头部信息,我们可以从中获得是否为POST方法,实体主体的总大小,边界字符串等,这些对于实体主体数据的解析都是非常重要的& 获取POST数据(实体主体)& 对POST数据进行解析& 将数据写入文件&&获取http请求报文头部信息& 利用nodejs中的 http.ServerRequest中获取1):
request.method&用来标识请求类型
request.headers&
其中我们关心两个字段:
content-type&包含了表单类型和边界字符串(下面会介绍)信息。
content-length&post数据的长度
关于content-type&
get请求的headers中没有content-type这个字段& post 的 content-type 有两种&
application/x-www-form-urlencoded 这种就是一般的文本表单用post传地数据,只要将得到的data用querystring解析下就可以了& multipart/form-data 文件表单的传输,也是本文介绍的重点&&&&获取POST数据问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
如何利用php 的exec执行nodejs文件? 如下执行却执行失败
public function execTask ($dirPath)
$serverPath = self::$serverP
exec("node httpd.js $serverPath",$info, $val);
var_dump($info);
echo "$val";
如果仅仅是exec("node -v $serverPath",$info, $val);却可以输出版本号,执行成功。求解答,谢谢。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
我也有类似的用法,所以除了有能读出消息的之外,还有能直接后台执行的功能,都是通过进程实现的
* 返回的汉语文字信息在windows中是GB2312编码,需要手动改成UTF8
iconv("GB2312","UTF-8",$read);
* @param $cmd
* @return array
public function execFront($cmd)
$response = array();
$handle = popen("$cmd 2&&1", 'r');
while ($read = fread($handle, 20096)) {
if(!mb_detect_encoding($read, 'UTF-8', true))
iconv("GB2312","UTF-8",$read);
$response[] = trim($read);
pclose($handle);
* @param $cmd
public function execBackend($cmd)
if (substr(php_uname(), 0, 7) == "Windows"){
pclose(popen("start cmd /c ". $cmd, "r"));
exec($cmd . " & /dev/null &");
分享到微博?
你好!看起来你挺喜欢这个内容,但是你还没有注册帐号。 当你创建了帐号,我们能准确地追踪你关注的问题,在有新答案或内容的时候收到网页和邮件通知。还能直接向作者咨询更多细节。如果上面的内容有帮助,记得点赞 (????)? 表示感谢。
明天提醒我
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:
扫扫下载 Appnodejs可否读取远程文件到本地有没有像php file_get_contents($url)
该问题被发起重新开启投票
投票剩余时间:
之前被关闭原因:
该问题被发起删除投票
投票剩余时间:
距离悬赏到期还有:
参与关闭投票者:
关闭原因:
该问题已经被锁定
锁定原因:()
保护原因:避免来自新用户不合宜或无意义的致谢、跟帖答案。
该问题已成功删除,仅对您可见,其他人不能够查看。
http.get 试试这个
不是您所需,查看更多相关问题与答案
德问是一个专业的编程问答社区,请
后再提交答案
关注该问题的人
共被浏览 (5615) 次4459人阅读
nodejs(5)
前几天碰到了一个需求,允许接收前端用户上传的文件。
当时为了解决问题索性就上github搜了下,找了一个基于nodejs的开发插件。
后来功能实现后觉得意犹未尽,于是自己想试试去写一个类似功能的插件,方便以后拓展,然后就这么开始了。
先来说说应用层的http,数据从前端是怎么被它包装然后传到服务器的。
我们可以在浏览器中查看我们发一个请求的时候包什么格式的,例如我们访问百度时得到的请求包内容:
Remote Address:180.97.33.107:443
Request URL:/
Request Method:GET
Status Code:200 OK
Request Headers
:method:GET
:scheme:https
:version:HTTP/1.1
accept:text/html,application/xhtml+xml,application/q=0.9,image/webp,*/*;q=0.8
accept-encoding:gzip, deflate, sdch
accept-language:zh-CN,q=0.8,q=0.6
cookie:BAIDUPSID=A757FA7DF43B; locale=
user-agent:Mozilla/5.0 (M Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36
Response Headers
bdpagetype:2
bdqid:0x9ca30abd
cache-control:private
content-encoding:gzip
content-type:text/html
date:Sat, 04 Apr 2015 07:42:42 GMT
expires:Sat, 04 Apr 2015 07:42:42 GMT
server:bfe/1.0.8.1
set-cookie:BDSVRTM=124; path=/
set-cookie:BD_HOME=1; path=/
set-cookie:H_PS_PSSID=11193_________8498; path=/; domain=.
set-cookie:__bsi=_31_38_R_N_124_0303_C02F_Y_I_I; expires=Sat, 04-Apr-15 07:42:47 GMT; domain=; path=/
status:200 OK
version:HTTP/1.1
相同的,服务器在接收到前端发来的请求时,经过一些逻辑处理,也会对前端发送一个数据包,包头格式如下:
bdpagetype:2
bdqid:0x9ca30abd
cache-control:private
content-encoding:gzip
content-type:text/html
date:Sat, 04 Apr 2015 07:42:42 GMT
expires:Sat, 04 Apr 2015 07:42:42 GMT
server:bfe/1.0.8.1
set-cookie:BDSVRTM=124; path=/
set-cookie:BD_HOME=1; path=/
set-cookie:H_PS_PSSID=11193_________8498; path=/; domain=.
set-cookie:__bsi=_31_38_R_N_124_0303_C02F_Y_I_I; expires=Sat, 04-Apr-15 07:42:47 GMT; domain=; path=/
status:200 OK
version:HTTP/1.1
那么数据包的核心就是服务器返回给客户端的内容,也就是包体,一般情况下,我们在写代码与客户端交互式不会去单独处理包头的内容(由http底层处理,淡然也可以人工干涉),我们只关心返回给前端什么样的数据也就是包体。
下面我们直接说说常用的post方法,如果你写过一点PHP,那么你肯定记得,在PHP里面,进行文件上传的时候,我们可以直接使用全局变量 $_FILE[‘name’ ]来获取已经被临时存储的文件信息。
但是实际上,POST数据实体,会根据数据量的大小进行分包传送,然后再从这些数据包里面分析出哪些是文件的元数据,那些是文件本身的数据。
PHP是底层做了封装,但是在nodejs里面,这个看似常见的功能却是需要自己来实现的。这篇文章主要就是介绍如何使用nodejs来解析post数据。
简单的说就是我们通过nodejs的http模块得到的文件上传数据是一个半成品,我们需要对数据进行拆分,找到那些是包头,哪些是包体。如果对接收到的数据直接进行拼接,那么结果就变成了这样子。
包头,包体都在一起。
关于content-type
get请求的headers中没有content-type这个字段post 的 content-type 有两种
application/x-www-form-urlencoded
这种就是一般的文本表单用post传地数据,只要将得到的data用querystring解析下就可以了
multipart/form-data
文件表单的传输,也是本文介绍的重点
获取POST数据
前面已经说过,post数据的传输是可能分包的,因此必然是异步的。post数据的接受过程如下:
var postData = '';
request.addListener("data", function(postDataChunk) {
// 有新的数据包到达就执行
postData += postDataC
console.log("Received POST data chunk '"+
postDataChunk + "'.");
request.addListener("end", function() {
// 数据传输完毕
console.log('post data finish receiving: ' + postData );
注意,对于非文件post数据,上面以字符串接收是没问题的,但其实 postDataChunk 是一个 buffer 类型数据,在遇到二进制时,这样的接受方式存在问题。
POST数据的解析(multipart/form-data)
在解析POST数据之前,先介绍一下post数据的格式:
multipart/form-data类型的post数据
例如我们有表单如下
action="/cgi/handle"
enctype="multipart/form-data"
method="post"&
What is your name?
type="text" name="submit-name"&&
What files are you sending?
type="file" name="files"&&
type="submit" value="Send"&
type="reset"&
若用户在text字段中输入‘Neekey’,并且在file字段中选择文件‘text.txt’,那么服务器端收到的post数据如下:
Content-Disposition: form- name="submit-name"
Content-Disposition: form- name="files"; filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
--AaB03x--
若file字段为空:
Content-Disposition: form- name="submit-name"
Content-Disposition: form- name="files"; filename=""
Content-Type: text/plain
--AaB03x--
若将file 的 input修改为可以多个文件一起上传:
action="/cgi/handle"
enctype="multipart/form-data"
method="post"&
What is your name?
type="text" name="submit-name"&&
What files are you sending?
type="file" name="files" multiple="multiple"&&
type="submit" value="Send"&
type="reset"&
那么在text中输入‘Neekey’,并在file字段中选中两个文件’a.jpg’和’b.jpg’后:
Content-Disposition: form- name="submit-name"
Content-Disposition: form- name="files"; filename="a.jpg"
Content-Type: image/jpeg
/* data of a.jpg */
Content-Disposition: form- name="files"; filename="b.jpg"
Content-Type: image/jpeg
/* data of b.jpg */
--AaB03x--// 可以发现 两个文件数据部分,他们的name值是一样的
简单总结下post数据的规则
1.不同字段数据之间以边界字符串分隔:
--boundary\r\n // 注意,如上面的headers的例子,分割字符串应该是 ------WebKitFormBoundaryuP1WvwP2LyvHpNCi\r\n
2.每一行数据用”CR LF”(\r\n)分隔
3.数据以 边界分割符 后面加上 –结尾,如:
------WebKitFormBoundaryuP1WvwP2LyvHpNCi--\r\n
4.每个字段数据的header信息(content-disposition/content-type)和字段数据以一个空行分隔:\r\n\r\n
关于form具体的内容可以看下W3C的文档:
If the user selected a second (image) file "file2.gif", the user agent might construct the parts as follows:
Content-Type: multipart/form- boundary=AaB03x
Content-Disposition: form- name="submit-name"
Content-Disposition: form- name="files"
Content-Type: multipart/ boundary=BbC04y
Content-Disposition: filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
Content-Disposition: filename="file2.gif"
Content-Type: image/gif
Content-Transfer-Encoding: binary
...contents of file2.gif...
--BbC04y--
--AaB03x--
数据解析基本思路
必须使用buffer来进行post数据的解析
利用文章一开始的方法(data += chunk, data为字符串 ),可以利用字符串的操作,轻易地解析出各自端的信息,但是这样有两个问题:
文件的写入需要buffer类型的数据
二进制buffer转化为string,并做字符串操作后,起索引和字符串是不一致的(若原始数据就是字符串,一致),因此是先将不总的buffer数据的toString()复制给一个字符串,再利用字符串解析出个数据的start,end位置这样的方案也是不可取的。
利用边界字符串来分割各字段数据
每个字段数据中,使用空行(\r\n\r\n)来分割字段信息和字段数据
所有的数据都是以\r\n分割
利用上面的方法,我们以某种方式确定了数据在buffer中的start和end,利用buffer.splice( start, end ) 便可以进行文件写入了.
其实github上有一个很不错的开源插件,有兴趣可以去看一下:
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:106325次
积分:1842
积分:1842
排名:千里之外
原创:74篇
转载:22篇
阅读:4939
(1)(1)(1)(1)(3)(9)(10)(8)(21)(23)(19)(1)(2)node.js解决获取图片真实文件类型的问题_node.js
遇到一个需求:假定有一个图片文件,真实的类型为jpg,而有人偷懒把jpg直接复制一张,存为同名的png文件,这样在as3读取文件时不会遇到问题,但手机c++在读取文件时却遇到问题了 - -!
现在就需要写一个程序,遍历所有文件夹下的文件,查找文件格式“不正常”的文件。我们的资源主要是gif、png、jpg,最开始,我到网上找到一篇:根据二进制流及文件头获取文件类型mime-type,然后读取文件二进制的头信息,获取其真实的文件类型,对与通过后缀名获得的文件类型进行比较。
复制代码 代码如下:
var fd = fs.openSync(new_file_path, 'r');
var buffer = new Buffer(8);
var mineType = mime.lookup(new_file_path);
var fileType = mime.extension(mineType);
fs.readSync(fd, buffer, 0, 8, 0);
var newBuf = buffer.slice(0, 4);
var head_1 = newBuf[0].toString(16);
var head_2 = newBuf[1].toString(16);
var head_3 = newBuf[2].toString(16);
var head_4 = newBuf[3].toString(16);
var head_iden = head_1 + head_2;
var tempFileType = FILE_TYPE_CONFIG[head_iden];
if (!tempFileType) {
head_iden += head_3;
tempFileType = FILE_TYPE_CONFIG[head_iden];
if (!tempFileType) {
var msg = "Unknow fileType " + new_file_path + '-' + fileT
showLog(msg);
if (tempFileType != fileType) {
var msg = "Error fileType" + new_file_path + '-' + fileType + '|' + tempFileType + '--正确的图像文件格式';
showLog(msg);
g_errorFileTypArr.push(msg);
后来搜索node image相关的信息时,找到这篇文章:node.js module ranking&& (images)
然后筛选到一个模块“node-imageinfo”,写了一个例子进行测试(故意把jpg文件直接修改后缀名为png):
它的源码,有兴趣可以研究一下:
复制代码 代码如下:
function readUInt32(buffer, offset, bigEndian) {
if (buffer.readUInt32) {
return buffer.readUInt32(offset, bigEndian);
if (bigEndian) {
if (buffer.readUInt32BE) {
return buffer.readUInt32BE(offset);
value = (buffer[offset] && 24) + (buffer[offset+1] && 16) + (buffer[offset+2] && 8) + buffer[offset+3];
if (buffer.readUInt32LE) {
return buffer.readUInt32LE(offset);
value = buffer[offset] + (buffer[offset+1] && 8) + (buffer[offset+2] && 16) + (buffer[offset+3] && 24);
function readUInt16(buffer, offset, bigEndian) {
if (buffer.readUInt16) {
return buffer.readUInt16(offset, bigEndian);
if (bigEndian) {
if (buffer.readUInt16BE) {
return buffer.readUInt16BE(offset);
value = (buffer[offset] && 8) + buffer[offset+1];
if (buffer.readUInt16LE) {
return buffer.readUInt16LE(offset);
value = buffer[offset] + (buffer[offset+1] && 8);
function readBit(buffer, offset, bitOffset) {
if (bitOffset & 7) {
offset += Math.floor(bitOffset / 8);
bitOffset = bitOffset % 8;
var b = buffer[offset];
if (bitOffset & 7) {
b &&&= (7 - bitOffset);
var val = b & 0x01;
function readBits(buffer, offset, bitOffset, bitLen, signed) {
var val = 0;
if (signed) {
if (readBit(buffer, offset, bitOffset) & 0) {
bitOffset++;
var bytes = [];
for (var i = 0; i & bitL i++) {
var b = readBit(buffer, offset, bitOffset + i);
if (i&0 && (bitLen - i) % 8 == 0) {
bytes.push(val);
val &&= 1;
bytes.push(val);
val = new Buffer(bytes);
val.negative = neg?true:
function imageInfoPng(buffer) {
var imageHeader = [0x49, 0x48, 0x44, 0x52],
if (!checkSig(buffer, pos, imageHeader)) {
type: 'image',
format: 'PNG',
mimeType: 'image/png',
width: readUInt32(buffer, pos, true),
height: readUInt32(buffer, pos+4, true),
function imageInfoJpg(buffer) {
var pos = 2,
len = buffer.length,
sizeSig = [0xff, [0xc0, 0xc2]];
while (pos & len) {
if (checkSig(buffer, pos, sizeSig)) {
type: 'image',
format: 'JPG',
mimeType: 'image/jpeg',
width: readUInt16(buffer, pos+2, true),
height: readUInt16(buffer, pos, true),
var size = readUInt16(buffer, pos, true);
function imageInfoGif(buffer) {
var pos = 6;
type: 'image',
format: 'GIF',
mimeType: 'image/gif',
width: readUInt16(buffer, pos, false),
height: readUInt16(buffer, pos+2, false),
function imageInfoSwf(buffer) {
var pos = 8,
bitPos = 0,
if (buffer[0] === 0x43) {
// If you have zlib available ( npm install zlib ) then we can read compressed flash files
buffer = require('zlib').inflate(buffer.slice(8, 100));
catch (ex) {
// Can't get width/height of compressed flash files... yet (need zlib)
type: 'flash',
format: 'SWF',
mimeType: 'application/x-shockwave-flash',
width: null,
height: null,
var numBits = readBits(buffer, pos, bitPos, 5)[0];
bitPos += 5;
val = readBits(buffer, pos, bitPos, numBits, true);
var xMin = (numBits & 9 ? readUInt16(val, 0, true) : val[0]) * (val.negative ? -1 : 1);
bitPos += numB
val = readBits(buffer, pos, bitPos, numBits, true);
var xMax = (numBits & 9 ? readUInt16(val, 0, true) : val[0]) * (val.negative ? -1 : 1);
bitPos += numB
val = readBits(buffer, pos, bitPos, numBits, true);
var yMin = (numBits & 9 ? readUInt16(val, 0, true) : val[0]) * (val.negative ? -1 : 1);
bitPos += numB
val = readBits(buffer, pos, bitPos, numBits, true);
var yMax = (numBits & 9 ? readUInt16(val, 0, true) : val[0]) * (val.negative ? -1 : 1);
type: 'flash',
format: 'SWF',
mimeType: 'application/x-shockwave-flash',
width: Math.ceil((xMax - xMin) / 20),
height: Math.ceil((yMax - yMin) / 20),
function checkSig(buffer, offset, sig) {
var len = sig.
for (var i = 0; i & i++) {
var b = buffer[i+offset],
s = sig[i],
if ('number' == typeof s) {
for (var k in s) {
var o = s[k];
if (o === b) {
module.exports = function imageInfo(buffer, path) {
var pngSig = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
var jpgSig = [0xff, 0xd8, 0xff];
var gifSig = [0x47, 0x49, 0x46, 0x38, [0x37, 0x39], 0x61];
var swfSig = [[0x46, 0x43], 0x57, 0x53];
if (checkSig(buffer, 0, pngSig)) return imageInfoPng(buffer);
if (checkSig(buffer, 0, jpgSig)) return imageInfoJpg(buffer);
if (checkSig(buffer, 0, gifSig)) return imageInfoGif(buffer);
if (checkSig(buffer, 0, swfSig)) return imageInfoSwf(buffer);

我要回帖

更多关于 nodejs和php 的文章

 

随机推荐