使用请求承诺时无法设置 Koajs 的 ctx.status 和 ctx.body
Cannot set Koajs' ctx.status and ctx.body when using request-promise
我目前正在编写验证 Shopify 应用程序的手动设置,类似于他们在 NodeJS and Express. For the application, I'm using NodeJS and the Koa framework. I'm also using @koa/router 中设置路由和尝试使用请求承诺来发出外部 HTTP 请求的方式。我不能使用 Shopify 的 Koa 身份验证中间件,因为它不能与路由器一起使用,我需要让代码库在未来支持其他电子商务平台(BigCommerce、Magento 等)。
当我获得访问令牌或错误消息时,我无法在承诺的 .then()
和 .catch()
方法中更改 Koa 的 ctx.status 和 ctx.body。就好像它只是被忽略了一样。
我为获取访问令牌进行了以下设置:
const KoaRouter = require('@koa/router'),
const nonce = require('nonce')();
const querystring = require('querystring');
const crypto = require('crypto');
const dotenv = require('dotenv').config();
const request = require('request-promise');
const koaRequest = require('koa-http-request');
// Get Shopify information from the .env file
const apiKey = process.env.SHOPIFY_API_KEY;
const apiSecret = process.env.SHOPIFY_API_SECRET;
const scopes = process.env.SHOPIFY_SCOPE;
const router = new KoaRouter();
const getInstallURL = (shop) => {
const state = nonce();
const forwardingAddress = 'https://aecd64c2.ngrok.io'
const redirectUri = forwardingAddress + '/shopify/auth/callback';
return {
"url": 'https://' + shop +
'/admin/oauth/authorize?client_id=' + apiKey +
'&scope=' + scopes +
'&state=' + state +
'&redirect_uri=' + redirectUri,
"state": state
};
}
const verifyHMAC = (query, hmac) => {
const map = Object.assign({}, query);
delete map['hmac'];
const message = querystring.stringify(map);
const providedHmac = Buffer.from(hmac, 'utf-8');
const generatedHash = Buffer.from(
crypto
.createHmac('sha256', apiSecret)
.update(message)
.digest('hex'),
'utf-8'
);
let hashEquals = false;
// timingSafeEqual will prevent any timing attacks. Arguments must be buffers
try {
hashEquals = crypto.timingSafeEqual(generatedHash, providedHmac)
// timingSafeEqual will return an error if the input buffers are not the same length.
} catch (e) {
hashEquals = false;
};
return hashEquals;
};
const requestAccessToken = (shop, code) => {
const accessTokenRequestUrl = 'https://' + shop + '/admin/oauth/access_token';
const accessTokenPayload = {
client_id: apiKey,
client_secret: apiSecret,
code,
};
console.log('Requesting accessToken for ' + shop + "!");
return request.post(accessTokenRequestUrl, { json: accessTokenPayload });
};
router.get('/shopify/auth', async (ctx, next) => {
const shop = ctx.request.query.shop;
console.log(shop);
if (shop) {
const ret = getInstallURL(shop);
console.log(ret)
ctx.cookies.set('state', ret['state']);
ctx.redirect(ret['url']);
} else {
ctx.status=400;
ctx.body='Missing shop parameter. Please add ?shop=your-development-shop.myshopify.com to your request';
}
});
router.get('/shopify/auth/callback', async (ctx, next) => {
const { shop, hmac, code, state } = ctx.request.query;
const stateCookie = ctx.cookies.get('state');
console.log(ctx.request.query);
console.log(stateCookie);
if (state !== stateCookie) {
ctx.status = 403;
ctx.body='Request origin cannot be verified';
}
if (shop && hmac && code) {
if (!verifyHMAC(ctx.request.query, hmac)) {
ctx.status = 400;
ctx.body='HMAC validation failed';
}
console.log('Verified HMAC. Now need to get access token');
requestAccessToken(shop, code).then(
(accessTokenResponse) => {
const accessToken = accessTokenResponse.access_token;
console.log('Access Token = ' + accessToken);
ctx.status= 200;
ctx.body= "Got an access token, let's do something with it";
}
).catch(
(error) => {
console.log('An error has occurred!');
console.log(error.statusCode);
console.log(error.error.error_description);
console.log(ctx.status);
ctx.status = error.statusCode;
ctx.body= error.error.error_description;
console.log(ctx.status);
}
)
} else {
ctx.status = 400;
ctx.body='Required parameters missing';
}
});
module.exports = router;
如何让 Koa 的上下文变量在 Promise 中工作?
您能否按如下方式编辑 requestAccessToken
函数。如果函数未定义为异步,则不能使用 .then()
方法。
const requestAccessToken = async (shop, code) => {
const accessTokenRequestUrl = 'https://' + shop + '/admin/oauth/access_token';
const accessTokenPayload = {
client_id: apiKey,
client_secret: apiSecret,
code,
};
console.log('Requesting accessToken for ' + shop + "!");
return await request.post(accessTokenRequestUrl, { json: accessTokenPayload });
};
我目前正在编写验证 Shopify 应用程序的手动设置,类似于他们在 NodeJS and Express. For the application, I'm using NodeJS and the Koa framework. I'm also using @koa/router 中设置路由和尝试使用请求承诺来发出外部 HTTP 请求的方式。我不能使用 Shopify 的 Koa 身份验证中间件,因为它不能与路由器一起使用,我需要让代码库在未来支持其他电子商务平台(BigCommerce、Magento 等)。
当我获得访问令牌或错误消息时,我无法在承诺的 .then()
和 .catch()
方法中更改 Koa 的 ctx.status 和 ctx.body。就好像它只是被忽略了一样。
我为获取访问令牌进行了以下设置:
const KoaRouter = require('@koa/router'),
const nonce = require('nonce')();
const querystring = require('querystring');
const crypto = require('crypto');
const dotenv = require('dotenv').config();
const request = require('request-promise');
const koaRequest = require('koa-http-request');
// Get Shopify information from the .env file
const apiKey = process.env.SHOPIFY_API_KEY;
const apiSecret = process.env.SHOPIFY_API_SECRET;
const scopes = process.env.SHOPIFY_SCOPE;
const router = new KoaRouter();
const getInstallURL = (shop) => {
const state = nonce();
const forwardingAddress = 'https://aecd64c2.ngrok.io'
const redirectUri = forwardingAddress + '/shopify/auth/callback';
return {
"url": 'https://' + shop +
'/admin/oauth/authorize?client_id=' + apiKey +
'&scope=' + scopes +
'&state=' + state +
'&redirect_uri=' + redirectUri,
"state": state
};
}
const verifyHMAC = (query, hmac) => {
const map = Object.assign({}, query);
delete map['hmac'];
const message = querystring.stringify(map);
const providedHmac = Buffer.from(hmac, 'utf-8');
const generatedHash = Buffer.from(
crypto
.createHmac('sha256', apiSecret)
.update(message)
.digest('hex'),
'utf-8'
);
let hashEquals = false;
// timingSafeEqual will prevent any timing attacks. Arguments must be buffers
try {
hashEquals = crypto.timingSafeEqual(generatedHash, providedHmac)
// timingSafeEqual will return an error if the input buffers are not the same length.
} catch (e) {
hashEquals = false;
};
return hashEquals;
};
const requestAccessToken = (shop, code) => {
const accessTokenRequestUrl = 'https://' + shop + '/admin/oauth/access_token';
const accessTokenPayload = {
client_id: apiKey,
client_secret: apiSecret,
code,
};
console.log('Requesting accessToken for ' + shop + "!");
return request.post(accessTokenRequestUrl, { json: accessTokenPayload });
};
router.get('/shopify/auth', async (ctx, next) => {
const shop = ctx.request.query.shop;
console.log(shop);
if (shop) {
const ret = getInstallURL(shop);
console.log(ret)
ctx.cookies.set('state', ret['state']);
ctx.redirect(ret['url']);
} else {
ctx.status=400;
ctx.body='Missing shop parameter. Please add ?shop=your-development-shop.myshopify.com to your request';
}
});
router.get('/shopify/auth/callback', async (ctx, next) => {
const { shop, hmac, code, state } = ctx.request.query;
const stateCookie = ctx.cookies.get('state');
console.log(ctx.request.query);
console.log(stateCookie);
if (state !== stateCookie) {
ctx.status = 403;
ctx.body='Request origin cannot be verified';
}
if (shop && hmac && code) {
if (!verifyHMAC(ctx.request.query, hmac)) {
ctx.status = 400;
ctx.body='HMAC validation failed';
}
console.log('Verified HMAC. Now need to get access token');
requestAccessToken(shop, code).then(
(accessTokenResponse) => {
const accessToken = accessTokenResponse.access_token;
console.log('Access Token = ' + accessToken);
ctx.status= 200;
ctx.body= "Got an access token, let's do something with it";
}
).catch(
(error) => {
console.log('An error has occurred!');
console.log(error.statusCode);
console.log(error.error.error_description);
console.log(ctx.status);
ctx.status = error.statusCode;
ctx.body= error.error.error_description;
console.log(ctx.status);
}
)
} else {
ctx.status = 400;
ctx.body='Required parameters missing';
}
});
module.exports = router;
如何让 Koa 的上下文变量在 Promise 中工作?
您能否按如下方式编辑 requestAccessToken
函数。如果函数未定义为异步,则不能使用 .then()
方法。
const requestAccessToken = async (shop, code) => {
const accessTokenRequestUrl = 'https://' + shop + '/admin/oauth/access_token';
const accessTokenPayload = {
client_id: apiKey,
client_secret: apiSecret,
code,
};
console.log('Requesting accessToken for ' + shop + "!");
return await request.post(accessTokenRequestUrl, { json: accessTokenPayload });
};