Nodejs应用开发者注意:有没有人在用BAE做Nodejs应用,困扰于没法发邮件,用户验证通知都没法做?BCMS云消息也老是报非法参数。
Nodejs应用开发者注意:有没有人在用BAE做Nodejs应用,困扰于没法发邮件,用户验证通知都没法做?BCMS云消息也老是报非法参数。
var ak = process.env.BAE_ENV_AK;
var sk = process.env.BAE_ENV_SK;
var API_HOST = ‘http://bcms.api.duapp.com/rest/2.0/bcms/’;/*** 百度云消息API地址*/
function signPostData(uri, postData){ //
var signstr = “POST” + uri;
_.pairs(postData).forEach(function(pd){
signstr += pd[0] + “=” + pd[1];
});
signstr += sk;
console.log(signstr);
signstr = encodeURIComponent(signstr);
console.log(signstr);
return util.MD5(signstr);
}
exports.create = function (callback){ /*** 创建队列 http://developer.baidu.com/wiki/index.php?title=docs/cplat/mq/api#create*/
var uri = API_HOST + ‘queue’;
var now = Date.now();
var postData = { ‘access_token’:sk, ‘client_id’: ak, ‘method’: ‘create’,‘expires’: now,‘queue_alias_name’: ‘queue_another_name’,‘queue_type’:0, ‘timestamp’: now, ‘v’: ‘1.0’};
postData = _.extend(postData, {‘sign’: signPostData(uri, postData)});
console.log(postData);
request.post(uri, postData, callback); //这里调用了全局的一个request模块,检查过没有问题。
};
以上代码老是返回{“error_code”:30001,“error_msg”:“Request params not valid”,“request_id”:3806336952} 请求参数非法
之前尝试过自己搞smtp,但socket锁住了,BAE好像过不去,老是报address error,放到自己服务器能通过,现在只能考虑用BCMS方式。再不行,只能再在sinaapp上做个rest调用了。
Node.js 应用开发者注意:有没有人在用BAE做Node.js应用,困扰于没法发邮件,用户验证通知都没法做?BCMS云消息也老是报非法参数。
问题描述
使用百度应用引擎(BAE)开发Node.js应用时,遇到了无法发送邮件的问题。用户验证通知也无法正常工作。尝试使用BCMS云消息服务时,总是收到“非法参数”的错误信息。
示例代码分析
以下是一个尝试使用BCMS云消息服务的示例代码片段:
var ak = process.env.BAE_ENV_AK;
var sk = process.env.BAE_ENV_SK;
var API_HOST = 'http://bcms.api.duapp.com/rest/2.0/bcms/';
function signPostData(uri, postData) {
var signstr = "POST" + uri;
_.pairs(postData).forEach(function(pd) {
signstr += pd[0] + "=" + pd[1];
});
signstr += sk;
console.log(signstr);
signstr = encodeURIComponent(signstr);
console.log(signstr);
return util.MD5(signstr);
}
exports.create = function(callback) {
var uri = API_HOST + 'queue';
var now = Date.now();
var postData = {
'access_token': sk,
'client_id': ak,
'method': 'create',
'expires': now,
'queue_alias_name': 'queue_another_name',
'queue_type': 0,
'timestamp': now,
'v': '1.0'
};
postData = _.extend(postData, {'sign': signPostData(uri, postData)});
console.log(postData);
request.post(uri, postData, callback); // 这里调用了全局的一个request模块,检查过没有问题。
};
问题原因分析
从上述代码中可以看出,问题出在签名计算和请求参数的构建上。具体来说,签名字符串的构建可能存在问题,导致请求参数不合法。此外,request.post
方法可能需要正确处理表单数据。
解决方案
- 检查签名算法:确保签名字符串的构建符合BCMS的要求。可以参考官方文档中的签名算法进行调整。
- 使用正确的HTTP方法:确保请求方法为POST,并且表单数据正确编码。
- 使用第三方库:可以考虑使用第三方库如
axios
或node-fetch
来简化HTTP请求的处理。
示例代码优化
const axios = require('axios');
const crypto = require('crypto');
function signPostData(uri, postData) {
const signstr = `POST${uri}${Object.keys(postData)
.sort()
.map(key => key + '=' + postData[key])
.join('')}${process.env.BAE_ENV_SK}`;
return crypto.createHash('md5').update(signstr).digest('hex');
}
exports.createQueue = async () => {
const uri = 'http://bcms.api.duapp.com/rest/2.0/bcms/queue';
const now = Date.now();
const postData = {
access_token: process.env.BAE_ENV_SK,
client_id: process.env.BAE_ENV_AK,
method: 'create',
expires: now,
queue_alias_name: 'queue_another_name',
queue_type: 0,
timestamp: now,
v: '1.0'
};
postData.sign = signPostData(uri, postData);
try {
const response = await axios.post(uri, postData);
console.log(response.data);
} catch (error) {
console.error(error.response.data);
}
};
总结
通过上述优化后的代码,可以更好地处理签名和HTTP请求,从而解决BCMS云消息服务中的非法参数问题。如果问题仍然存在,建议查看官方文档或联系技术支持以获取更多帮助。
以上代码能表达意思,去掉了不相关的部分。
应该找BAE的客服
BCMS 接口文档
服务简介
百度云消息服务(Baidu Cloud Message Service, BCMS)是百度于2011年7月最新设计研发,并于2011年底推出的国内首个消息服务平台。BCMS为百度云计算平台上的所有应用提供高效,可靠,安全,便捷的消息服务。广大应用开发者可以使用BCMS在他们应用的分布式组件上自由的传递数据,并结合百度云计算平台的其它服务,创造出更有特色的精品应用
使用示例
var http = require('http');
var BCMS = require('bae-bcms');
var port = process.env.APP_PORT;
var hostname = process.env.BAE_ENV_ADDR_BCMS || 'bcms.api.duapp.com';
var server = http.createServer(function(req, res) {
res.writeHead(200, {
'Content-Type': 'text/html'
});
var ak = process.env.BAE_ENV_AK;
var sk = process.env.BAE_ENV_SK;
var options = {
host: hostname,
ak: ak,
sk: sk
}
var client = new BCMS(options);
var opt = {};
client.createQueue(opt, function(err, result){
if(err){
console.log(err);
return;
}
console.log(result);
});
});
server.listen(port);
接口列表
各个接口的options配置请参考百度开发者中心BCMS开发文档
BaeBCMS(options)
- 构造函数
- options {Object}: BCMS初始化选项
- host {String}: BCMS服务器地址
- ak {String}: 用户API key
- sk {String}: 用户Secret key
createQueue(options, callback)
- 创建一个队列
- options {Object}: 创建队列选项
- expires {Number}: 可选,签名有效期截止时间戳
- queue_type {Number}: 可选,队列的消费模式
- queue_alias_name {String}: 可选,队列别名
- callback(err, result): 调用成功,err为空,result为返回结果;调用失败,err返回的具体错误信息, result为空
dropQueue(options, callback)
- 取消一个队列
- options {Object}: 取消队列选项
- expires {Number}: 可选,签名有效期截止时间戳
- queue_name {String}: 队列名,该值为创建队列时返回的queue_name值
- callback(err, result): 调用成功,err为空,result为返回结果;调用失败,err返回的具体错误信息, result为空
subscribeQueue(options, callback)
- 注册一个订阅队列
- options {Object}: 注册选项
- destination {String}: 订阅通知的目标地址,不超过256字节,合法的destination类型,目前仅支持http://host/uri的格式
- queue_name {String}: 队列名,该值为创建队列时返回的queue_name值
- callback(err, result): 调用成功,err为空,result为返回结果;调用失败,err返回的具体错误信息, result为空
unsubscribeQueue(options, callback)
- 取消注册订阅队列
- options {Object}: 取消注册选项
- destination:订阅通知的目标地址,不超过256字节,合法的destination类型,目前仅支持http://host/uri的格式
- queue_name: 队列名,该值为创建队列时返回的queue_name值
- callback(err, result): 调用成功,err为空,result为返回结果;调用失败,err返回的具体错误信息, result为空
unsubscribeAllQueue(options, callback)
- 取消队列全部的注册订阅
- options {Object}: 取消队列选项
- queue_name: 队列名,该值为创建队列时返回的queue_name值
- callback(err, result): 调用成功,err为空,result为返回结果;调用失败,err返回的具体错误信息, result为空
grantQueue(options, callback)
- 授权分享该队列
- options {Object}: 授权选项
- queue_name {String}: 队列名,该值为创建队列时返回的queue_name值
- label {String}: 分享授权标识, 由开发者自己维护,在删除时需要此信息。最小长度为5个字符,最大长度为20个字符,必须为字母和数字的组合
- user {String}: 被授权的开发者百度账号, 百度passport用户名,或者百度passport注册的邮箱,或者百度passport注册的手机号
- usertype {Number}: 被授权的开发者百度账号类型 1:passport用户名, 默认值, 2:passport邮箱, 3:passport手机号
- actions {Array}: 授权的操作类型,例如 [‘drop’, ‘suspend’] 详见这里
- callback(err, result): 调用成功,err为空,result为返回结果;调用失败,err返回的具体错误信息, result为空
revokeQueue(options, callback)
- 回收授权分享队列
- options {Object}: 回收选项
- queue_name {String}: 队列名,该值为创建队列时返回的queue_name值
- label {String}: 分享授权标识, 由开发者自己维护,在删除时需要此信息。最小长度为5个字符,最大长度为20个字符,必须为字母和数字的组合
- callback(err, result): 调用成功,err为空,result为返回结果;调用失败,err返回的具体错误信息, result为空
suspendQueue(options, callback)
- 暂停队列消息的存取功能
- options {Object}: 回收选项
- queue_name {String}: 队列名,该值为创建队列时返回的queue_name值
- label {String}: 分享授权标识, 由开发者自己维护,在删除时需要此信息。最小长度为5个字符,最大长度为20个字符,必须为字母和数字的组合
- callback(err, result): 调用成功,err为空,result为返回结果;调用失败,err返回的具体错误信息, result为空
resumeQueue(options, callback)
- 恢复队列的消息存取功能
- options {Object}: 恢复选项
- queue_name {String}: 队列名,该值为创建队列时返回的queue_name值
- callback(err, result): 调用成功,err为空,result为返回结果;调用失败,err返回的具体错误信息, result为空
confirmQueue(options, callback)
- 通过token确认注册订阅生效
- options {Object}:确认选项
- queue_name {String}: 队列名,该值为创建队列时返回的queue_name值
- destination {String}: 订阅通知的目标地址,不超过256个字节,合法的类型目前只支持 http://host/uri
- token {String}: 确认令牌,最长不超过128个字节
- callback(err, result): 调用成功,err为空,result为返回结果;调用失败,err返回的具体错误信息, result为空
cancelQueue(options, callback)
- 通过token取消注册订阅
- options {Object}: 取消选项
- queue_name {String}: 队列名,该值为创建队列时返回的queue_name值
- destination {String}: 订阅通知的目标地址,不超过256个字节,合法的类型目前只支持 http://host/uri
- token {String}: 确认令牌,最长不超过128个字节
- callback(err, result): 调用成功,err为空,result为返回结果;调用失败,err返回的具体错误信息, result为空
publishMessage(options, callback)
- 向该队列发送消息
- options {String}: 发送消息选项
- queue_name {String}: 队列名,该值为创建队列时返回的queue_name值
- message {String}: 消息内容, 必须为文本,最大不超过256K字节,消息不能为空
- callback(err, result): 调用成功,err为空,result为返回结果;调用失败,err返回的具体错误信息, result为空
publishMultiMessages(options, callback)
- 批量向该队列发送消息
- options {Object}: 发送选项
- queue_name {String}: 队列名,该值为创建队列时返回的queue_name值
- messages {Array}: 每条消息内容, 必须为文本,最大不超过256K字节。消息不能为空。多个消息用json数组的形式表达,最多10个消息。
- callback(err, result): 调用成功,err为空,result为返回结果;调用失败,err返回的具体错误信息, result为空
fetchMessage(options, callback)
- 主动获取该队列的消息
- options {Object}: 获取选项
- queue_name {String}: 队列名,该值为创建队列时返回的queue_name值
- msg_id {Number}: 可选,指定查询消息起始id,如果是多模式队列,必须指定起始消息id;如果是单模式队,则不能指定起始消息ID
- fetch_num {Number}: 可选,消费消息个数,默认为1,最大为10
- callback(err, result): 调用成功,err为空,result为返回结果;调用失败,err返回的具体错误信息, result为空
mail(options, callback)
- 发送即时通讯的邮件消息
- options {Object}:发送邮件选项
- queue_name {String}: 队列名,该值为创建队列时返回的queue_name值
- message {String}: 每条消息内容, 必须为文本,最大不超过256K字节,不能为空
- address {Array} : 字符串数组,接收者的邮件地址,一次最多支持10个邮箱地址
- mail_subject {String}: 可选,邮件主题,最长不超过128字节。如果不指定将使用默认邮件主题:您有新的消息(来自百度消息服务)
- from {String}: 可选,发送者邮件地址
- callback(err, result): 调用成功,err为空,result为返回结果;调用失败,err返回的具体错误信息, result为空
兄弟, 我为了这个自己写了份bae发送邮件的模块.
请参考: http://pangwa.github.io/bae-message/
我计划再写一些基于bae云消息的其他服务, 有兴趣的话可以参与进来啊~
官方没有这个模块的说明…
我在百度上怎么找不到
// php like URL encode 这个你也能挖掘出来哈,后端的确用的php的encode 可以试试bae-push, bae-bcs
从你的描述来看,你在使用百度BAE(百度应用引擎)时遇到了发送邮件以及通过BCMS云消息服务时出现非法参数的问题。为了解决这些问题,我们可以尝试以下方法:
解决邮件发送问题
首先,解决邮件发送问题的最佳实践是使用成熟的邮件发送库,比如nodemailer
。这里是一个简单的示例:
const nodemailer = require('nodemailer');
let transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'your-email@gmail.com',
pass: 'your-password'
}
});
let mailOptions = {
from: 'your-email@gmail.com',
to: 'recipient-email@example.com',
subject: 'Hello ✔',
text: 'Hello world?',
html: '<b>Hello world?</b>'
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error);
}
console.log('Message sent: %s', info.messageId);
});
解决BCMS云消息问题
针对BCMS云消息的问题,我们可能需要重新审查请求参数的构造过程。以下是一些建议:
-
检查签名生成逻辑:确保
signPostData
函数正确处理了所有参数,并且按照官方文档中的规定生成了签名。 -
检查请求数据:确保所有必需的参数都已正确设置,并且与文档中的要求一致。
-
日志记录:增加更多的日志记录来跟踪请求的具体细节,这样可以帮助定位问题所在。
如果你已经确认请求参数没有问题,但仍然遇到错误,那么可能是BCMS服务本身存在某些限制或问题。这时可以考虑联系百度的技术支持寻求帮助。
结论
对于邮件发送问题,推荐使用nodemailer
等成熟的第三方库。对于BCMS云消息的问题,建议仔细检查请求参数的构造,并确保遵循官方文档。如果问题依旧无法解决,建议联系技术支持。