NodeJS 代理未按预期工作
NodeJS proxy not working as intended
请求的当前路由源自 localhost:3001,通过位于 localhost:3001/proxy 的同一本地主机上的代理 运行,然后请求路由到 Salesforce实例。代理是使用 ExpressJS 制作的,客户端应用程序是使用 AngularJS 制作的。注意:我确实记得在我的密码末尾标记我的安全令牌(Salesforce API 要求),尽管在使用 cURL 时,这似乎不是必需的。以下是一系列 HTTP 跟踪,有望提供一些线索:
来自 Angular.JS 应用程序的 HTTP 请求日志:
POST /proxy HTTP/1.1
Host: localhost:3001
Connection: keep-alive
Content-Length: 234
Pragma: no-cache
Cache-Control: no-cache
X-User-Agent: salesforce-toolkit-rest-javascript/v29.0
Origin: http://localhost:3001
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: application/json, text/plain, */*
SalesforceProxy-Endpoint: https://uniquename.salesforce.com/services/oauth2/token
Referer: http://localhost:3001/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: liveagent_oref=; liveagent_ptid=3c69c2f9-139d-4439-ba6c-fd8d9dcae101; liveagent_vc=5
grant_type=password&client_id=3MVGxyzxyzxyzxyz&client_secret=99889988&username=first.last%40email.com&password=pswdwACYodaYfHs
400 Bad Request
Object {error_description: "grant type not supported", error: "unsupported_grant_type"}
用于代理路由的相关Express.JS代码:
app.all('/proxy', function(req, res) {
var url = req.header('SalesforceProxy-Endpoint');
console.log(req.body); //prints all form data variables in JSON format
console.log(res.body); //undefined
request({url: url}).pipe(res).on('error', function(error){
//I think I may need to pipe more information using request?
console.log(error);
});
});
使用 cURL 请求详细信息:
curl -v https://uniquename.salesforce.com/services/oauth2/token
-d "grant_type=password" -d "client_id=3MVGxyzxyzxyzxyz"
-d "client_secret=99889988" -d "username=jfirst.last@email.com" -d "password=pswd"
> POST /services/oauth2/token HTTP/1.1
> User-Agent: curl/7.41.0
> Host: uniquename.salesforce.com
> Accept: */*
> Content-Length: 207
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 207 out of 207 bytes
< HTTP/1.1 200 OK
< Date: Wed, 29 Jul 2015 06:04:55 GMT
< Set-Cookie: BrowserId=auu1mgvHSMS1EedDEduz8Q;Path=/;Domain=.salesforce.com;Exp
ires=Sun, 27-Sep-2015 06:04:55 GMT
< Expires: Thu, 01 Jan 1970 00:00:00 GMT
< Pragma: no-cache
< Cache-Control: no-cache, no-store
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
<
{
"id":"https://test.salesforce.com/id/05390530530",
"issued_at":"1438132525896197",
"token_type":"Bearer",
"instance_url":"https://uniquename.salesforce.com",
"signature":"blahblah",
"access_token":"XXXXXXXXXXXXXXXXX"
}
* Connection #0 to
host uniquename.salesforce.com left intact
如您所见,我从 cURL 请求返回了有效响应。我怀疑代理有问题,因为它可能没有将所有表单数据转发给 Salesforce,但我不确定如何在 Express.JS 中调试它。我怀疑这是因为如果我尝试 curl https://uniquename.salesforce.com/services/oauth2/token
它 returns 相同的 unsupported_grant_type
错误。
我认为您没有代理 HTTP 请求中的所有内容。我在下面包含了一些代码,它们会将请求方法和请求 headers 传递给您的端点。也可以尝试使用 'request-debug' 库,以便您可以比较代理 HTTP 请求与您的 curl 请求并查看差异
var express = require('express');
var app = express();
var request = require('request');
require('request-debug')(request);
app.all('/proxy', function(req, res) {
var url = req.header('SalesforceProxy-Endpoint');
var options = {
url: url,
method: req.method,
headers: req.headers
}
request(options).pipe(res).on('error', function (error, response, body) {
if (!error && response.statusCode == 200) {
//TODO: do something useful with the response
} else {
console.log('ERROR: ' + error);
}
});
});
我终于通过切换到使用 cors-anywhere 代理来完成这项工作。我在端口 8080 上部署了我的 AngularJS 应用程序,在端口 3001 上部署了代理。我的包使用 npm
和 grunt
进行管理。这是代理的代码:
var host = 'localhost';
var port = 3001;
var cors_proxy = require('cors-anywhere');
cors_proxy.createServer().listen(port, host, function() {
console.log('CORS proxy running on ' + host + ':' + port);
});
下面是我在 AngularJS 中发出 HTTP 请求的方式(您必须在数据对象中填写您自己的凭据):
var login = {
method: 'POST',
url: 'http://localhost:3001/https://login.salesforce.com/services/oauth2/token',
data: 'grant_type=password&client_id='+encodeURIComponent(CLIENT_ID)+'&client_secret='+encodeURIComponent(CLIENT_SECRET)+'&username='+encodeURIComponent(EMAIL)+'&password='+encodeURIComponent(PASSWORD+USER_SECURITY_TOKEN),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': '*/*'
}
};
$http(login).success(function(response){
console.log(response);
})
.error( function(response, status){
console.log(response);
console.log("Status: " + status);
});
您可以使用 node server.js
命令 运行 代理,使用 grunt
运行 AngularJS 应用程序。我希望这对某人有所帮助,这是一个很难解决的问题。
请求的当前路由源自 localhost:3001,通过位于 localhost:3001/proxy 的同一本地主机上的代理 运行,然后请求路由到 Salesforce实例。代理是使用 ExpressJS 制作的,客户端应用程序是使用 AngularJS 制作的。注意:我确实记得在我的密码末尾标记我的安全令牌(Salesforce API 要求),尽管在使用 cURL 时,这似乎不是必需的。以下是一系列 HTTP 跟踪,有望提供一些线索:
来自 Angular.JS 应用程序的 HTTP 请求日志:
POST /proxy HTTP/1.1
Host: localhost:3001
Connection: keep-alive
Content-Length: 234
Pragma: no-cache
Cache-Control: no-cache
X-User-Agent: salesforce-toolkit-rest-javascript/v29.0
Origin: http://localhost:3001
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: application/json, text/plain, */*
SalesforceProxy-Endpoint: https://uniquename.salesforce.com/services/oauth2/token
Referer: http://localhost:3001/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: liveagent_oref=; liveagent_ptid=3c69c2f9-139d-4439-ba6c-fd8d9dcae101; liveagent_vc=5
grant_type=password&client_id=3MVGxyzxyzxyzxyz&client_secret=99889988&username=first.last%40email.com&password=pswdwACYodaYfHs
400 Bad Request
Object {error_description: "grant type not supported", error: "unsupported_grant_type"}
用于代理路由的相关Express.JS代码:
app.all('/proxy', function(req, res) {
var url = req.header('SalesforceProxy-Endpoint');
console.log(req.body); //prints all form data variables in JSON format
console.log(res.body); //undefined
request({url: url}).pipe(res).on('error', function(error){
//I think I may need to pipe more information using request?
console.log(error);
});
});
使用 cURL 请求详细信息:
curl -v https://uniquename.salesforce.com/services/oauth2/token
-d "grant_type=password" -d "client_id=3MVGxyzxyzxyzxyz"
-d "client_secret=99889988" -d "username=jfirst.last@email.com" -d "password=pswd"
> POST /services/oauth2/token HTTP/1.1
> User-Agent: curl/7.41.0
> Host: uniquename.salesforce.com
> Accept: */*
> Content-Length: 207
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 207 out of 207 bytes
< HTTP/1.1 200 OK
< Date: Wed, 29 Jul 2015 06:04:55 GMT
< Set-Cookie: BrowserId=auu1mgvHSMS1EedDEduz8Q;Path=/;Domain=.salesforce.com;Exp
ires=Sun, 27-Sep-2015 06:04:55 GMT
< Expires: Thu, 01 Jan 1970 00:00:00 GMT
< Pragma: no-cache
< Cache-Control: no-cache, no-store
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
<
{
"id":"https://test.salesforce.com/id/05390530530",
"issued_at":"1438132525896197",
"token_type":"Bearer",
"instance_url":"https://uniquename.salesforce.com",
"signature":"blahblah",
"access_token":"XXXXXXXXXXXXXXXXX"
}
* Connection #0 to
host uniquename.salesforce.com left intact
如您所见,我从 cURL 请求返回了有效响应。我怀疑代理有问题,因为它可能没有将所有表单数据转发给 Salesforce,但我不确定如何在 Express.JS 中调试它。我怀疑这是因为如果我尝试 curl https://uniquename.salesforce.com/services/oauth2/token
它 returns 相同的 unsupported_grant_type
错误。
我认为您没有代理 HTTP 请求中的所有内容。我在下面包含了一些代码,它们会将请求方法和请求 headers 传递给您的端点。也可以尝试使用 'request-debug' 库,以便您可以比较代理 HTTP 请求与您的 curl 请求并查看差异
var express = require('express');
var app = express();
var request = require('request');
require('request-debug')(request);
app.all('/proxy', function(req, res) {
var url = req.header('SalesforceProxy-Endpoint');
var options = {
url: url,
method: req.method,
headers: req.headers
}
request(options).pipe(res).on('error', function (error, response, body) {
if (!error && response.statusCode == 200) {
//TODO: do something useful with the response
} else {
console.log('ERROR: ' + error);
}
});
});
我终于通过切换到使用 cors-anywhere 代理来完成这项工作。我在端口 8080 上部署了我的 AngularJS 应用程序,在端口 3001 上部署了代理。我的包使用 npm
和 grunt
进行管理。这是代理的代码:
var host = 'localhost';
var port = 3001;
var cors_proxy = require('cors-anywhere');
cors_proxy.createServer().listen(port, host, function() {
console.log('CORS proxy running on ' + host + ':' + port);
});
下面是我在 AngularJS 中发出 HTTP 请求的方式(您必须在数据对象中填写您自己的凭据):
var login = {
method: 'POST',
url: 'http://localhost:3001/https://login.salesforce.com/services/oauth2/token',
data: 'grant_type=password&client_id='+encodeURIComponent(CLIENT_ID)+'&client_secret='+encodeURIComponent(CLIENT_SECRET)+'&username='+encodeURIComponent(EMAIL)+'&password='+encodeURIComponent(PASSWORD+USER_SECURITY_TOKEN),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': '*/*'
}
};
$http(login).success(function(response){
console.log(response);
})
.error( function(response, status){
console.log(response);
console.log("Status: " + status);
});
您可以使用 node server.js
命令 运行 代理,使用 grunt
运行 AngularJS 应用程序。我希望这对某人有所帮助,这是一个很难解决的问题。