express 如何实现请求转发
发布于 12 年前 作者 yiqianke 53171 次浏览 最后一次编辑是 8 年前

前端ajax进入nodejs,nodejs如何发送ajax到某台服务器? 代码如下,搞不清为什么app.get是可以的,app.post没有反应。http.request 里面都没有执行。

//routes.js
var sign = require('/sign');
//这个是 OK的
app.get('/api/getUser', function(req,res){
    sign.find(req,function(res,data){
        res.render('ruleConfig.html',{user:data});
    })
})
//这个没反应
app.post('/api/getUser', function(req,res){
    sign.find(req,function(res,data){
        res.contentType('json');
        res.write(JSON.stringify(data));
    res.end();
    })
})
//sign.js
var http = require('http');
exports.find = function(req,success){
    var headers = req.headers;
    headers.host = 'www.xxx.com';
    var options = {
	    host: 'www.xxx.com',
	    port: 80,
	    path: '/getUser',
	    method: 'GET',
	    headers: headers	
    };
    var req = http.request(options, function(res) {
	    res.setEncoding('utf8');
	    res.on('data', function (data) {
	      var data = JSON.parse(data);
	      success(res,data);
	    });
    });	
    req.on('error', function(e){
       console.log("auth_user error: " + e.message);
    });
    req.end();
}
20 回复

少了个括号: res.write(JSON.stringify(data);

嗯,这只是个简单的例子便于解释我的问题。已经更正了。请问真正导致不能转发的原因在哪里?

我提议两个方法给你试试

app.post('/api/getUser', function(req,res){
    sign.find(req,function(res,data){
        res.json(data);
    })
})

var req = http.request(options, function(res) {
	res.setEncoding('utf8');
	var str = '';
	res.on('data', function(d) {
	    str += d;
	});
	res.on('end', function () {
	    var data=JSON.parse(str);
	    success(res,data);
    });

@yiqianke

问题出在这里: success(res,data); 你里面的 res 不应该用在外面。 我很怀疑你的 get 可用。我的调好的例子在下面。

var express = require("express");
var app = express();
var sign = require('./hellosign');

app.get('/', function(req, res){
    var content = 'hello world<hr>';
    content += '<form action="/api/getUser">';
    content += '<input type="submit">';
    content += '</form>';
    res.send(content);
});

app.get('/data', function(req, res){
    res.send('{ "name": "hello world" }');
});

app.get('/api/getUser', function(req, res){
    sign.find(req, function(data){
        //res.render('ruleConfig.html',{user:data});
        res.contentType('json');
        //var data = { name: 'jack' };
        res.write(JSON.stringify(data));
        res.end();
    })
})

app.post('/api/getUser', function(req, res){
    sign.find(req, function(res, data){
        res.contentType('json');
        res.write(JSON.stringify(data));
        res.end();
    })
})

console.log('web server on port 8001');
app.listen(8001);

hellosign.js

var http = require('http');

exports.find = function(req, success){
    
    var headers = req.headers;
    headers.host = 'localhost';
    
    var options = {
        host: 'localhost',
        port: 8001,
        path: '/data',
        method: 'GET',
        headers: headers    
    };
    
    req = http.request(options, function(res) {
        res.setEncoding('utf8');
        res.on('data', function (data) {
            console.log('>>> ', data);
            data = JSON.parse(data);
            success(data);
        });
    });
    
    req.on('error', function(e){
       console.log("auth_user error: " + e.message);
    });
    
    req.end();
}

@leapon 非常感谢您的帮助,不过用了您的例子还是和我的问题一样,get可以通过,但是把form表单里的提交方式改成post就会得不到结果。是不是要改header信息?

content += '<form action="/api/getUser" method="post">';

@yiqianke 我的测试通过。你用我的代码试了吗?

@leapon @alvis接收页面post请求的时候的头部带了content-length属性。但是转发的时候又用的是get方法。去掉这个属性就搞定了。但是觉得这样处理不妥。有没有好办法?

@leapon delete headers['content-length'];

/**
 * 简单的HTTP代理服务器
 *
 * @author 老雷<leizongmin@gmail.com>
 */
var http = require('http');

// 记录日志
var log = function () {
  var now = new Date().toISOString();
  arguments[0] = '[' + now + '] ' + arguments[0];
  console.log.apply(console, arguments);
};

// 获取请求的headers,去掉host和connection
var getHeader = function (req) {
  var ret = {};
  for (var i in req.headers) {
    if (!/host|connection/i.test(i)) {
      ret[i] = req.headers[i];
    }
  }
  return ret;
};

// 获取请求的路径
var getPath = function (req) {
  var url = req.url;
  if (url.substr(0, 7).toLowerCase() === 'http://') {
    var i = url.indexOf('/', 7);
    if (i !== -1) {
      url = url.substr(i);
    }
  }
  return url;
};

// 代理请求
var counter = 0;
var onProxy = function (req, res) {
  counter++;
  var num = counter;
  var opt = {
    host:     req.headers.host,
    path:     getPath(req),
    method:   req.method,
    headers:  getHeader(req)
  };
  log('#%d\t%s http://%s%s', num, req.method, opt.host, opt.path);
  var req2 = http.request(opt, function (res2) {
    res.writeHead(res2.statusCode, res2.headers);
    res2.pipe(res);
    res2.on('end', function () {
      log('#%d\tEND', num);
    });
  });
  if (/POST|PUT/i.test(req.method)) {
    req.pipe(req2);
  } else {
    req2.end();
  }
  req2.on('error', function (err) {
    log('#%d\tERROR: %s', num, err.stack);
    res.end(err.stack);
  });
};


// 启动http服务器
var server = http.createServer(onProxy);
server.listen(8080);
log('proxy server listen on http://127.0.0.1:8080');

@yiqianke 难道是 post 不带 content-length 属性。 post 的内容和头部是分开的,所以没有 content-length 属性?有点道理。不确切。

不错。这个就是我想要的,多谢

@leapon 搞反了。POST请求才需要 content-length 属性,否则服务器不知道什么时候才接收完数据。 因为请求头是通过 \r\n\r\n 来表示结束的,剩下的POST数据木有结束标志,只能通过content-length来确定。

利用pipe处理转发是最简单的

@leizongmin 很有参考意义,解决了我很多疑问

@leizongmin 你好,使用pipe做下载时要怎么处理啊? 服务端返回的是二进制文件,经过pipe传到前端的文件是一个乱码的文件,这个要怎么处理编码的问题?

@zfeidy 文件是什么样的内容?举个例子

@leizongmin 已经弄好了,之所以乱码是因为有

res.setEncoding('utf8');

这句话,去掉就OK。不过要实现代理上传的话感觉还是蛮麻烦的!我做了一个感觉不太好,需要使用node服务器中转一次,这样效率就低了。你有好的思路吗?

@leizongmin mark 老雷的代码,老早了~

回到顶部