由大众资助的工具应该属于大众。
这就是我想要向你展示如何用不到 300 行代码打造你自己的众筹网站的原因。本教程中的所有内容都是开源的,我们只使用其他开源技术,如 Node.js、MongoDB 和 Balanced Payments。
0. 快速入门
如果你只想获取最终的众筹网站,请克隆 crowdfunding-tuts 仓库 并进入 /demo
文件夹。
你只需要设置你的配置变量,就可以开始使用了!对于想要了解详细细节的人,请继续阅读。
1. 使用 Express 设置一个基本的 Node.js 应用
如果你还没有这样做,你需要 安装 Node.js。(当然)
为你的应用创建一个新文件夹。我们将使用 Express.js 框架 来让事情变得更加轻松。为了安装 Express 节点模块,在你的应用文件夹的命令行中运行以下命令
npm install express
接下来,创建一个名为 app.js
的文件,它将作为你的主要服务器逻辑。以下代码将初始化一个简单的 Express 应用,
它只为你的众筹网站提供一个基本的首页和筹款页面。
// Configuration
var CAMPAIGN_GOAL = 1000; // Your fundraising goal, in dollars
// Initialize an Express app
var express = require('express');
var app = express();
app.use("/static", express.static(__dirname + '/static')); // Serve static files
app.use(express.bodyParser()); // Can parse POST requests
app.listen(1337); // The best port
console.log("App running on http://localhost:1337");
// Serve homepage
app.get("/",function(request,response){
// TODO: Actually get fundraising total
response.send(
""+
"Your Crowdfunding Campaign
"+
"raised ??? out of $"+CAMPAIGN_GOAL.toFixed(2)+"
"+
"Fund This"
);
});
// Serve funding page
app.get("/fund",function(request,response){
response.sendfile("fund.html");
});
创建另一个名为 fund.html
的文件。它将成为你的筹款页面。
Donation Page:
可选地,你也可以在 /static/fancy.css
中包含一个样式表,
以便你的网站在接下来的教程中看起来不那么糟糕。
@import url(https://fonts.googleapis.com/css?family=Raleway:200);
body {
margin: 100px;
font-family: Raleway; /* Sexy font */
font-weight: 200;
}
最后,在命令行中运行 node app
来启动你的服务器!
在 http://localhost:1337
上查看你目前为止的众筹网站。
首页将显示你在 app.js
的配置部分设置的活动目标。捐赠页面目前还不功能,因此在接下来的章节中,我将向你展示如何从你的赞助者那里接受和汇总信用卡付款。
2. 开始使用 Balanced Payments
Balanced Payments 不仅仅是一个支付处理器。他们已经开源了他们的整个网站,他们的聊天记录是公开的,他们甚至在公开场合讨论他们的路线图。 这些人真正理解开放性。
最重要的是,你甚至不需要注册就可以开始使用 Balanced!
只需点击此链接,他们就会为你生成一个全新的测试市场,
你之后可以用一个帐户来认领它。请记住保持此选项卡处于打开状态,或者保存 URL,以便稍后可以回到你的测试市场。
点击侧边栏中的“设置”选项卡,并记下你的市场 URI 和 API 密钥。
将这些变量复制到 app.js
的配置部分,如下所示
// Configuration
var BALANCED_MARKETPLACE_URI = "/v1/marketplaces/TEST-YourMarketplaceURI";
var BALANCED_API_KEY = "YourAPIKey";
var CAMPAIGN_GOAL = 1000; // Your fundraising goal, in dollars
现在,让我们切换回 fund.html
来创建我们的实际支付页面。
首先,我们将包含并初始化 Balanced.js。这个 JavaScript 库将安全地标记用户的信用卡信息,因此你的服务器永远不需要直接处理这些信息。这意味着,你将免受 PCI 监管。将以下代码追加到 fund.html
中,用你的实际市场 URI 替换 BALANCED_MARKETPLACE_URI
接下来,创建表单本身,要求用户的姓名、他们想要捐赠的金额和其他信用卡信息。我们还将添加一个隐藏的输入,用于 Balanced.js 将提供的信用卡标记。下面的表单包含测试 Visa 信用卡的默认值。将此追加到 fund.html
请注意,付款按钮不会直接提交表单,而是调用一个 charge()
函数,我们将在下文中实现它。charge()
函数将从 Balanced.js 获取信用卡标记,
将其添加为一个隐藏的输入,并提交表单。将此追加到 fund.html
此表单将发送一个 POST 请求到 /pay/balanced
,我们将在 app.js
中处理它。现在,我们只想显示卡标记 URI。将以下代码粘贴到 app.js
的末尾
// Pay via Balanced
app.post("/pay/balanced",function(request,response){
// Payment Data
var card_uri = request.body.card_uri;
var amount = request.body.amount;
var name = request.body.name;
// Placeholder
response.send("Your card URI is: "+request.body.card_uri);
});
重启你的应用(Ctrl-C 退出,然后 node app
重新启动),并返回 http://localhost:1337
。
你的支付表单现在应该看起来像这样
表单的默认值将可以直接使用,因此只需点击“使用信用卡付款”。(确保你已经用你的实际测试市场的 URI 替换了 fund.html
中的 BALANCED_MARKETPLACE_URI
!)你的服务器将愉快地用生成的卡 URI 标记响应。
接下来,我们将使用此标记来实际扣款!
3. 通过 Balanced Payments 扣款
在我们开始扣款之前(哈哈),让我们安装另外两个 Node.js 模块,以便于使用。
在命令行中运行以下命令
# A library for simplified HTTP requests.
npm install request
npm install q
一个 Promises 库,以便愉快地处理异步调用并避免回调地狱。
由于我们将向 Balanced 发出多个调用,因此让我们创建一个辅助方法。以下函数返回一个 Promise,表示 Balanced API 已经响应了我们刚刚发送的 HTTP 请求。将此代码追加到 app.js
// Calling the Balanced REST API
var Q = require('q');
var httpRequest = require('request');
function _callBalanced(url,params){
// Promise an HTTP POST Request
var deferred = Q.defer();
httpRequest.post({
url: "https://api.balancedpayments.com"+BALANCED_MARKETPLACE_URI+url,
auth: {
user: BALANCED_API_KEY,
pass: "",
sendImmediately: true
},
json: params
}, function(error,response,body){
// Handle all Bad Requests (Error 4XX) or Internal Server Errors (Error 5XX)
if(body.status_code>=400){
deferred.reject(body.description);
return;
}
// Successful Requests
deferred.resolve(body);
});
return deferred.promise;
}
现在,当我们提交捐赠表单时,我们不再仅仅显示卡标记 URI,而是要
- 使用卡 URI 创建一个帐户
- 对上述帐户进行给定金额的扣款(注意:你需要将其转换为美分,以供 Balanced API 使用)
- 在数据库中记录交易(注意:我们现在跳过这一步,并在下一章中介绍)
- 渲染来自交易的个性化消息
用以下内容替换上一章中的 app.post("/pay/balanced", ... );
回调
// Pay via Balanced
app.post("/pay/balanced",function(request,response){
// Payment Data
var card_uri = request.body.card_uri;
var amount = request.body.amount;
var name = request.body.name;
// TODO: Charge card using Balanced API
/*response.send("Your card URI is: "+request.body.card_uri);*/
Q.fcall(function(){
// Create an account with the Card URI
return _callBalanced("/accounts",{
card_uri: card_uri
});
}).then(function(account){
// Charge said account for the given amount
return _callBalanced("/debits",{
account_uri: account.uri,
amount: Math.round(amount*100) // Convert from dollars to cents, as integer
});
}).then(function(transaction){
// Donation data
var donation = {
name: name,
amount: transaction.amount/100, // Convert back from cents to dollars.
transaction: transaction
};
// TODO: Actually record the transaction in the database
return Q.fcall(function(){
return donation;
});
}).then(function(donation){
// Personalized Thank You Page
response.send(
""+
"Thank you, "+donation.name+"!
"+
"You donated $"+donation.amount.toFixed(2)+".
"+
"Return to Campaign Page
"+
"
"+
"Here's your full Donation Info:
"+
"<pre>"+JSON.stringify(donation,null,4)+"</pre>"
);
},function(err){
response.send("Error: "+err);
});
});
现在重启你的应用,并再次通过捐赠页面付款。(注意:为了支付手续费,你需要支付超过 0.50 美元的金额)这一次,你会得到一个完整的付款完成页面,其中包含个性化的信息!
此外,如果你查看测试市场仪表板中的交易选项卡,你应该会发现你的余额中已经添加了资金。
我们快到了!接下来,让我们在 MongoDB 数据库中记录捐赠。
4. 使用 MongoDB 记录捐赠
MongoDB 是一个流行的开源 NoSQL 数据库。NoSQL 特别适合快速原型开发,因为它具有动态模式。换句话说,你可以随意创建东西。
如果将来你想记录有关每个捐赠的额外详细信息,比如捐赠者的电子邮件地址、奖励等级、最喜欢的颜色等,这将非常有用。
启动一个 MongoDB 数据库,并获取其 URI。你可以使用像 MongoHQ 这样的服务来使用远程数据库,但对于本教程,让我们在本地运行 MongoDB (在你的计算机上安装和运行 MongoDB 的说明)。
完成此操作后,将 MongoDB URI 添加到 app.js
开头的配置部分。
// Configuration
var MONGO_URI = "mongodb://localhost:27017/test";
var BALANCED_MARKETPLACE_URI = "/v1/marketplaces/TEST-YourMarketplaceURI";
var BALANCED_API_KEY = "YourAPIKey";
var CAMPAIGN_GOAL = 1000; // Your fundraising goal, in dollars
现在,让我们安装 Node.js 的原生 MongoDB 驱动程序
npm install mongodb
将以下代码添加到 app.js
的末尾。这将返回一个 Promise,表示我们已经在 MongoDB 中记录了捐赠。
// Recording a Donation
var mongo = require('mongodb').MongoClient;
function _recordDonation(donation){
// Promise saving to database
var deferred = Q.defer();
mongo.connect(MONGO_URI,function(err,db){
if(err){ return deferred.reject(err); }
// Insert donation
db.collection('donations').insert(donation,function(err){
if(err){ return deferred.reject(err); }
// Promise the donation you just saved
deferred.resolve(donation);
// Close database
db.close();
});
});
return deferred.promise;
}
之前,我们跳过了实际记录到数据库的捐赠。
返回并用以下内容替换代码的那部分
// TODO: Actually log the donation with MongoDB
/*return Q.fcall(function(){
return donation;
});*/
// Record donation to database
return _recordDonation(donation);
重启你的应用,并进行另一次捐赠。如果你在你的 MongoDB 实例上运行 db.donations.find()
,你将找到你刚刚记录的捐赠!
只剩下最后一步了…
最后,我们将使用这些记录的捐赠来计算我们筹集了多少资金。
5. 完成捐赠
无论是为了展示进度还是为了炫耀,你都需要告诉潜在的赞助者你的活动已经筹集了多少资金。
要获取总捐赠金额,只需查询 MongoDB 中的所有捐赠金额,并将它们加起来。以下是如何使用 MongoDB 进行操作,以及它的异步 Promise。将此代码追加到 app.js
// Get total donation funds
function _getTotalFunds(){
// Promise the result from database
var deferred = Q.defer();
mongo.connect(MONGO_URI,function(err,db){
if(err){ return deferred.reject(err); }
// Get amounts of all donations
db.collection('donations')
.find( {}, {amount:1} ) // Select all, only return "amount" field
.toArray(function(err,donations){
if(err){ return deferred.reject(err); }
// Sum up total amount, and resolve promise.
var total = donations.reduce(function(previousValue,currentValue){
return previousValue + currentValue.amount;
},0);
deferred.resolve(total);
// Close database
db.close();
});
});
return deferred.promise;
}
现在,让我们回到我们提供基本首页的地方。让我们更改它,以实际计算你的总资金,并向世界展示你的活动进展到何种程度。
// Serve homepage
app.get("/",function(request,response){
// TODO: Actually get fundraising total
/*response.send(
""+
"Your Crowdfunding Campaign
"+
"raised ??? out of $"+CAMPAIGN_GOAL.toFixed(2)+"
"+
"Fund This"
);*/
Q.fcall(_getTotalFunds).then(function(total){
response.send(
""+
"Your Crowdfunding Campaign
"+
"raised $"+total.toFixed(2)+" out of $"+CAMPAIGN_GOAL.toFixed(2)+"
"+
"Fund This"
);
});
});
重启应用,并查看你的最终首页。
它…太美了。
你会看到你的总金额已经包含了上一章记录的捐赠。通过捐赠页面进行另一次付款,并观察你的筹款总额上升。
恭喜你,你刚刚创建了自己的众筹网站!
– – –
在 Hacker News 上讨论
关于 Nick Liow
Thiel Fellow & Mozilla WebFWD 校友。使用 Commonly.cc 为创意共享进行众筹。
关于 Robert Nyman [荣誉编辑]
技术布道师 & Mozilla Hacks 编辑。发表关于 HTML5、JavaScript 和开放网络的演讲和博客。Robert 是 HTML5 和开放网络的坚定支持者,自 1999 年以来一直在从事 Web 前端开发工作 - 在瑞典和纽约市。他定期在 http://robertnyman.com 上发布博客,喜欢旅行和结识新朋友。
14 条评论