如何使用 Node.js 创建一个 API 代理?
How to make an API proxy with Node.js?
由于 GFW 屏蔽了包括 flickr 在内的一些 IP,我想用 Node.js 创建一个 API 代理,但是我在 http 服务器中打开 GET 请求时遇到了问题。这是我的代码:
var http = require('http');
var qs = require('querystring');
var curl = require('request');
var serverPort = 3000;
http.createServer(function (request, response) {
if(request.method === "GET") {
response.writeHead(401, {'Content-Type': 'text/html'});
response.write('<!doctype html><html><head><title>401</title></head><body>401: Unauthorized</body></html>');
response.end();
} else if(request.method === "POST") {
if (request.url === "/") {
var requestBody = '';
request.on('data', function(data) {
requestBody += data;
if(requestBody.length > 1e7) {
response.writeHead(413, 'Request Entity Too Large', {'Content-Type': 'text/html'});
response.end('413: Request Entity Too Large');
}
});
request.on('end', function() {
var body = getrequest();
if (body === false) {
response.writeHead(502, 'Bad Gateway', {'Content-Type': 'text/html'});
response.end('502: Bad Gateway');
} else {
response.writeHead(200, {'Content-Type': 'text/html'});
response.write(body);
response.end();
}
});
} else {
response.writeHead(404, 'Resource Not Found', {'Content-Type': 'text/html'});
response.end('<!doctype html><html><head><title>404</title></head><body>404: Resource Not Found</body></html>');
}
} else {
response.writeHead(405, 'Method Not Supported', {'Content-Type': 'text/html'});
return response.end('<!doctype html><html><head><title>405</title></head><body>405: Method Not Supported</body></html>');
}
}).listen(serverPort);
function getrequest(){
return curl('https://api.flickr.com/services/rest/?method=flickr.photosets.getList&api_key={{insert_ur_api_key}}&user_id={{insert_ur_user_id}}&format=json', function (error, response, body) {
if (error) {
return false;
} else {
return body;
}
});
}
console.log('Server running at localhost:'+serverPort);
在此示例中,我使用了 request
包(使用 npm install request
进行安装)。
错误信息如下:
_http_outgoing.js:655
throw new TypeError('First argument must be a string or Buffer');
^
TypeError: First argument must be a string or Buffer
at write_ (_http_outgoing.js:655:11)
at ServerResponse.write (_http_outgoing.js:630:10)
at IncomingMessage.<anonymous> (/Users/aero/Documents/Design/0522-aerofotea api/www/index.js:28:20)
at emitNone (events.js:105:13)
at IncomingMessage.emit (events.js:207:7)
at endReadableNT (_stream_readable.js:1045:12)
at _combinedTickCallback (internal/process/next_tick.js:102:11)
at process._tickCallback (internal/process/next_tick.js:161:9)
我觉得问题是response.write(getrequest());
getrequest是一个async action,你应该使用callback或者promisify。如果使用回调,getrequest函数应该是这样的:
function getrequest(callback){
curl('https://api.flickr.com/services/rest/?method=flickr.photosets.getList&api_key={{insert_ur_api_key}}&user_id={{insert_ur_user_id}}&format=json', (error, response, body)=> {
if (error) {
callback(error);
return;
}
callback(null, body);
});
}
然后像这样使用它:
request.on('end', function() {
getrequest((err, body)=>{
if (err) {
response.writeHead(502, 'Bad Gateway', {'Content-Type': 'text/html'});
response.end('502: Bad Gateway');
} else {
response.writeHead(200, {'Content-Type': 'text/html'});
response.write(body);
response.end();
}
})
})
由于 GFW 屏蔽了包括 flickr 在内的一些 IP,我想用 Node.js 创建一个 API 代理,但是我在 http 服务器中打开 GET 请求时遇到了问题。这是我的代码:
var http = require('http');
var qs = require('querystring');
var curl = require('request');
var serverPort = 3000;
http.createServer(function (request, response) {
if(request.method === "GET") {
response.writeHead(401, {'Content-Type': 'text/html'});
response.write('<!doctype html><html><head><title>401</title></head><body>401: Unauthorized</body></html>');
response.end();
} else if(request.method === "POST") {
if (request.url === "/") {
var requestBody = '';
request.on('data', function(data) {
requestBody += data;
if(requestBody.length > 1e7) {
response.writeHead(413, 'Request Entity Too Large', {'Content-Type': 'text/html'});
response.end('413: Request Entity Too Large');
}
});
request.on('end', function() {
var body = getrequest();
if (body === false) {
response.writeHead(502, 'Bad Gateway', {'Content-Type': 'text/html'});
response.end('502: Bad Gateway');
} else {
response.writeHead(200, {'Content-Type': 'text/html'});
response.write(body);
response.end();
}
});
} else {
response.writeHead(404, 'Resource Not Found', {'Content-Type': 'text/html'});
response.end('<!doctype html><html><head><title>404</title></head><body>404: Resource Not Found</body></html>');
}
} else {
response.writeHead(405, 'Method Not Supported', {'Content-Type': 'text/html'});
return response.end('<!doctype html><html><head><title>405</title></head><body>405: Method Not Supported</body></html>');
}
}).listen(serverPort);
function getrequest(){
return curl('https://api.flickr.com/services/rest/?method=flickr.photosets.getList&api_key={{insert_ur_api_key}}&user_id={{insert_ur_user_id}}&format=json', function (error, response, body) {
if (error) {
return false;
} else {
return body;
}
});
}
console.log('Server running at localhost:'+serverPort);
在此示例中,我使用了 request
包(使用 npm install request
进行安装)。
错误信息如下:
_http_outgoing.js:655
throw new TypeError('First argument must be a string or Buffer');
^
TypeError: First argument must be a string or Buffer
at write_ (_http_outgoing.js:655:11)
at ServerResponse.write (_http_outgoing.js:630:10)
at IncomingMessage.<anonymous> (/Users/aero/Documents/Design/0522-aerofotea api/www/index.js:28:20)
at emitNone (events.js:105:13)
at IncomingMessage.emit (events.js:207:7)
at endReadableNT (_stream_readable.js:1045:12)
at _combinedTickCallback (internal/process/next_tick.js:102:11)
at process._tickCallback (internal/process/next_tick.js:161:9)
我觉得问题是response.write(getrequest());
getrequest是一个async action,你应该使用callback或者promisify。如果使用回调,getrequest函数应该是这样的:
function getrequest(callback){
curl('https://api.flickr.com/services/rest/?method=flickr.photosets.getList&api_key={{insert_ur_api_key}}&user_id={{insert_ur_user_id}}&format=json', (error, response, body)=> {
if (error) {
callback(error);
return;
}
callback(null, body);
});
}
然后像这样使用它:
request.on('end', function() {
getrequest((err, body)=>{
if (err) {
response.writeHead(502, 'Bad Gateway', {'Content-Type': 'text/html'});
response.end('502: Bad Gateway');
} else {
response.writeHead(200, {'Content-Type': 'text/html'});
response.write(body);
response.end();
}
})
})