请教一个在http.request的response事件中的嵌套data事件中Nodejs的http跳转问题(已解决,statusCode错误地取默认值200所致)

请教一个在http.request的response事件中的嵌套data事件中Nodejs的http跳转问题(已解决,statusCode错误地取默认值200所致)

我按照如下流程执行了一序列的嵌套操作 1,普通的get请求handler ↓ 2,发起post请求 ↓ 3,post请求的response事件的handler ↓ 3,注册post请求的response对象的data事件 ↓ 4,data事件中使用1中的response对象通过setHeader执行跳转

但实际的结果是在浏览器端仍然停留在1中的请求上,并没有执行4中所执行的跳转。本人也是刚开始学习nodejs,不明白问题出在哪里。恳请对此熟悉的大侠指点一下!先谢过!


6 回复

好的,让我们来分析并解决这个问题。根据你的描述,问题出在 statusCode 错误地取了默认值 200,导致跳转没有正确执行。我们可以通过检查 response.statusCode 并在需要时进行跳转来解决这个问题。

下面是具体的代码示例:

const http = require('http');

function makeGetRequest() {
    const options = {
        hostname: 'example.com',
        port: 80,
        path: '/api/get-data',
        method: 'GET'
    };

    const req = http.request(options, (res) => {
        res.on('data', (chunk) => {
            console.log(`Received data: ${chunk}`);
            
            // 检查响应状态码是否为3xx(重定向)
            if (res.statusCode >= 300 && res.statusCode < 400) {
                const location = res.headers.location;
                if (location) {
                    console.log(`Redirecting to: ${location}`);
                    // 发起新的GET请求到重定向的URL
                    makeGetRequest(location);
                } else {
                    console.error('Location header not found in the response.');
                }
            }
        });
        
        res.on('end', () => {
            console.log('Response ended.');
        });
    });

    req.on('error', (e) => {
        console.error(`Problem with request: ${e.message}`);
    });

    req.end();
}

// 调用函数发起初始GET请求
makeGetRequest();

解释:

  1. 发起GET请求:首先,我们创建一个HTTP GET请求。
  2. 处理响应:当接收到响应时,我们监听 data 事件以获取响应数据。
  3. 检查状态码:在 data 事件的处理器中,我们检查响应的状态码是否在 300-399 范围内,这表示一个重定向。
  4. 处理重定向:如果状态码是重定向状态码,我们从响应头中获取 Location 字段,并发起一个新的GET请求到该位置。
  5. 结束事件:最后,我们监听 end 事件以确保响应已经完全接收完毕。

这样,当服务器返回重定向状态码时,客户端会自动跟随重定向,并不会停留在原始请求页面。这样就能解决你遇到的问题。


补充一下4中有设置statusCode和end()调用,没有遗漏什么东西

请上代码

感谢朴灵的回复,代码如下

app.get('/weibo', function(req, res){
	if (!req.query.code)
	{
		console.log(req.query);
		res.statusCode = 400;
		res.end('error: '+req.query.error_description);
		return;
	}
var data = ['client_id='+weibo.config.client_id,
	   	   'client_secret='+weibo.config.client_secret,
	   	   'grant_type=authorization_code',
	   	   'redirect_uri='+weibo.config.redirect_uri,
	   	   'code='+req.query.code].join('&amp;');
httpclient.post('https://api.weibo.com/oauth2/access_token', data, function(resp){
	console.log('weibo.token string: '+resp);
	weibo.token = JSON.parse(resp);
	console.log('weibo.token.access_token: '+weibo.token.access_token);
	console.log('now we will go back to /');
	res.statucCode = 302;
	res.setHeader('Location', '/');
	res.end();
});

});

/weibo是weib open api的回调uri,是正常从 https://api.weibo.com/oauth2/authorize 跳转回来的,实际console打印中有 weibo.token string: weibo.token.access_token: now we will go back to / 的输出,但是没有跳转;app.get()实现是《深入浅出nodejs》中的example,就不列举了;httpclient是对http.request/https.request直观的封装,代码如下

var httpclient = {};
httpclient.post = function(u, data, callback){
	var urlparts = url.parse(u, true);
	var request;
	if (urlparts.protocol === 'http:')
	{
		request = http.request({
			hostname: urlparts.host,
			port: urlparts.port || 80,
			method: 'POST',
			path: urlparts.pathname
		});		
	}
	else if (urlparts.protocol === 'https:')
	{
		request = https.request({
			hostname: urlparts.host,
			port: urlparts.port || 443,
			method: 'POST',
			path: urlparts.pathname
		});
	}
	else
	{
		console.error('unsupported protocol: '+urlparts.protocol);
		return;
	}

	request.on('response', function(res){
		res.on('data', function(d){
			callback(d.toString());
		});
	});
	request.setHeader('Content-Type', 'application/x-www-form-urlencoded');
	request.setHeader('Content-Length', data.length);
	request.end(data);
}

module.exports = httpclient;

解决了就好,我还特意去翻了翻Express框架中response.redirect()的实现代码,呵呵。

根据你的描述,问题可能是由于在 http.requestresponse 事件中,statusCode 可能没有正确地从响应头中获取到,导致你误以为 statusCode 是默认的 200,从而未能执行跳转。

在 Node.js 中,HTTP 响应的状态码可以通过 response.statusCode 来获取。你需要确保在处理 response 事件时,检查 response.statusCode 是否为重定向状态码(如 301, 302, 307 等),然后相应地进行处理。

以下是一个示例代码,展示了如何正确处理 HTTP 跳转:

const http = require('http');

function makeRequest(url) {
    const options = {
        hostname: new URL(url).hostname,
        port: 80,
        path: new URL(url).pathname,
        method: 'GET',
        headers: {
            'User-Agent': 'node.js'
        }
    };

    const req = http.request(options, (res) => {
        console.log(`STATUS: ${res.statusCode}`);
        
        if ([301, 302, 307].includes(res.statusCode)) {
            // 如果是重定向状态码,提取 Location 头并重新请求
            const location = res.headers.location;
            if (location) {
                console.log(`Redirecting to: ${location}`);
                makeRequest(location);
            } else {
                console.error('Location header not found in redirect response');
            }
        } else {
            // 处理非重定向状态码的响应
            let data = '';
            res.on('data', (chunk) => {
                data += chunk;
            });

            res.on('end', () => {
                console.log(data);
            });
        }
    });

    req.on('error', (e) => {
        console.error(`Problem with request: ${e.message}`);
    });

    req.end();
}

// 初始请求
makeRequest('http://example.com');

在这个示例中,我们创建了一个 makeRequest 函数来发起 HTTP GET 请求。当接收到重定向状态码时,我们提取 Location 头并重新发起请求。对于其他状态码,我们继续读取数据并在结束时打印出来。

希望这段代码能帮助你理解如何处理 HTTP 跳转,并解决你的问题。

回到顶部