В этом посте рассказывается о создании веб-сайта для продажи продуктов. Мы настроили клиентское приложение Vue и серверное приложение Node.js. Приложения используют библиотеки Javascript Stripe для обработки платежей. Мы развертываем клиентское приложение на Amazon S3 и развертываем сервер Node.js в облаке с помощью Heroku.

В этом уроке мы собираемся создать веб-сайт для продажи ручных наборов палочек в Интернете. Он будет называться Липкий! Для создания этого сайта нам потребуются страница отображения продукта, страница заказа и страница сведений о подтверждении. Мы принимаем платежи с использованием клиентских и серверных библиотек Javascript Stripe.

Для создания внешнего интерфейса мы будем использовать Vue 2 с vue-router для маршрутизации на стороне клиента. Интерфейсное приложение будет отвечать за сбор информации о пользователях и отправку запроса в Stripe для получения специального токена. Как только мы получим этот токен от Stripe, наш клиентский код перенаправит токен на наш сервер, чтобы инициировать оплату.

Сервер будет сделан из Node.js с использованием Express и связанных с ним служебных библиотек. Будет две конечных точки. Один для создания нового платежа, а другой для возврата сведений о конкретном платеже на основе уникального идентификатора, который мы получаем от Stripe.

Чтобы создать это приложение и начать продавать в Интернете, мы собираемся использовать сторонние сервисы. Чтобы создать реальный веб-сайт, который принимает фактические платежи в Интернете, вам необходимо подписаться на следующие услуги и найти свои специальные ключи API.

  • Stripe: Stripe - это текущий стандарт для разработчиков, принимающих платежи в США. У Stripe много конкурентов, но обширная документация и простота использования сделали его фактическим выбором для обработки онлайн-платежей. Мы собираемся использовать их [клиентскую сторону] (https://stripe.com/docs/stripe.js?) Библиотеку Javascript и их серверную часть [пакет Node.js] (https://stripe.com/ документы / api / node ).

  • Amazon Simple Storage Service (S3): Amazon S3 является частью Amazon Web Services, инфраструктуры, которая поддерживает очень большую часть Интернета. Простое решение для хранения данных (S3) позволяет размещать статические ресурсы, такие как веб-страницы, изображения или видео, и делать их глобально доступными. Вы можете создать бесплатную учетную запись AWS здесь.

  • Heroku: Heroku - это платформа облачных приложений, приобретенная Salesforce. Это упрощает задачу развертывания и обслуживания облачной инфраструктуры. Мы собираемся использовать Heroku [интерфейс командной строки (CLI)] (https://devcenter.heroku.com/articles/getting-started-with-nodejs#set-up) для развертывания нашего сервера Node.js на Интернет.

Фронтенд-приложение

Сначала мы собираемся создать интерфейсное приложение Vue.js. Это часть веб-сайта, которую увидит пользователь. В конечном итоге он будет размещен на Amazon S3, но сначала мы должны все настроить.

Основная команда Vue.js поддерживает коллекцию генераторов для создания новых проектов. В этом руководстве мы собираемся использовать простой шаблон webpack, чтобы быстро запустить и запустить клиентский Vue.js. Это будет включать пользовательскую настройку Webpack и определенные файлы `.vue`, которые содержат наши HTML, CSS и Javascript для выделенных компонентов.

Если вы не использовали Vue до того, как вас ждет угощение! Если у вас есть опыт работы с Vue, эта настройка должна быть для вас очень простой.

Мы собираемся использовать для стилизации Bulma, которая представляет собой библиотеку CSS на основе Flexbox. Если вы новичок в использовании CSS Flexbox, вы можете прочитать статью Scotch.io здесь. Глубокие знания Flexbox не являются обязательным условием для этого руководства.

Создайте приложение Vue.js

Создайте приложение статического веб-сайта Vue.js с помощью следующих команд в интерфейсе командной строки.

$ vue init webpack-simple YOUR_APP_NAME
$ cd YOUR_APP_NAME
$ npm install
$ npm install vue-router moment — save

Это создает наш новый проект и включает дополнительные зависимости для маршрутизации на стороне клиента и форматирования даты.

Создайте экземпляр приложения

Наш файл src / main.js станет нервным центром для нашего приложения. Это первый вызываемый файл, он будет вызывать все наши компоненты и связывать наше приложение Javascript со страницей index.html. Давайте импортируем в этот файл все компоненты, библиотеки и настройки, необходимые для нашего приложения.

./src/main.js

// Environment configuration
if (process.env.NODE_ENV === ‘production’) {
 window.endpoint = ‘https://stickly.herokuapp.com';
} else {
 window.endpoint = ‘http://localhost:3000';
}
// Global Variables
window.moment = require(‘moment’);
window.axios = require(‘axios’);
window.axios.defaults.headers.common[‘X-Requested-With’] = ‘XMLHttpRequest’;
import Vue from ‘vue’
import VueRouter from ‘vue-router’
import App from ‘./components/App.vue’
import Product from ‘./components/Product.vue’
import Order from ‘./components/Order.vue’
import Complete from ‘./components/Complete.vue’
Vue.use(VueRouter);
// Register routes
const routes = [
 { name: ‘home’, path: ‘/’, component: Product },
 { name: ‘order’, path: ‘/order’, component: Order },
 { name: ‘order-complete’, path: ‘/order-complete/:id’, component: Complete }
];
const router = new VueRouter({
 routes
});
// Instantiate application to the DOM
new Vue({
 router,
 el: ‘#app’,
 data(){
     return {};
 },
 render: h => h(App)
});

Первое, что мы делаем здесь, - это определяем, находимся ли мы в производственной среде или в среде разработки. Это значение будет установлено веб-пакетом, когда мы запустим npm run dev (для разработки) или npm run build (для производства). В зависимости от среды мы устанавливаем глобальную переменную, прикрепленную к объекту окна браузера, которая определяет, по какому URL-адресу наше приложение Vue будет отправлять запросы XHR (ajax). Для выполнения асинхронных запросов из фона мы будем использовать axios.

Затем мы регистрируем необходимые нам компоненты и привязываем их к конкретным маршрутам. Это шаблон, необходимый для настройки маршрутизации на стороне клиента с помощью vue-router, официального пакета маршрутизации Vue.js, поддерживаемого основной командой Vue.js.

Нам также потребуется изменить нашу страницу index.html, чтобы включить в нее библиотеку javascript Stripe, структуру Bulma CSS, классы стилей и Font Awesome.

./index.html

<!DOCTYPE html>
<html lang=”en”>
<head>
 <meta charset=”utf-8">
 <meta http-equiv=”X-UA-Compatible” content=”IE=edge”>
 <meta name=”viewport” content=”width=device-width, initial-scale=1">
<title>Stickly</title>
<!-- Styles -->
 <link rel=’stylesheet’ href=’https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css'>
 <link rel=”stylesheet” href=”https://cdnjs.cloudflare.com/ajax/libs/bulma/0.5.1/css/bulma.css">
 <link rel=”stylesheet” href=”./css/main.css”>
</head>
<body>
 <div class=”hero is-fullheight”>
 <div id=’app’></div>
 </div>
<!-- Scripts -->
 <script type=”text/javascript” src=”https://js.stripe.com/v2/"></script>
 <script src=”/dist/build.js”></script>
</body>
</html>

Наше приложение Vue.js будет привязано к index.html через тег id «app», где оно будет монтировать наш компонент App. Этот компонент приложения будет отображать большую часть нашего контента и логики нашего приложения Vue.js. Он отображает раздел навигации и специальный компонент «‹router-view› ‹/router-view›«. Этот компонент сообщает vue-router, где монтировать наши представления. Маршрутизатор берет текущий URL-адрес и соответственно монтирует компонент в это пространство.

./src/components/App.vue

<template>
 <div id=”app”>
 <!-- Nav -->
 <div class=”hero-head”>
 <div class=”container”>
 <nav class=”nav”>
 <div class=”container”>
 <div class=”nav-left”>
 <router-link to=”/” class=”nav-item”>Stickly</router-link>
 </div>
 <span class=”nav-toggle”>
 <span></span>
 <span></span>
 <span></span>
 </span>
 <div class=”nav-right nav-menu”>
 <a class=”nav-item” href=’[email protected]’>
 Contact
 </a>
 </div>
 </div>
 </nav>
 </div>
 </div>
  <router-view></router-view>
 </div>
</template>
<script>
export default {
 name: ‘app’,
 data () {
 return {}
 }
}
</script>

Компонент приложения - это сердце нашего приложения. Все другие наши компоненты Vue будут отображаться там, где находится компонент просмотра маршрутизатора. Таким образом, нам не нужно дублировать код для панели навигации или заголовков HTML на каждой странице.

В нашем файле * main.js * мы определили, что когда пользователь попадает в корень нашего приложения, компонент продукта должен отображаться. Давайте определимся сейчас!

Создайте страницу продукта

Страница продукта - это целевая страница, которая побуждает пользователя купить наш продукт, в данном случае набор палочек. Существует шаблон с открытым исходным кодом под названием dansup / bulma-templates, который мы можем использовать для быстрого стилизации страницы продукта. Существует множество примеров шаблонов для Bulma, которые вы можете просматривать [здесь] () и здесь, в зависимости от того, что вы создаете. Шаблон страницы продукта - хорошая отправная точка, хотя я внес некоторые незначительные изменения.

./src/components/Product.vue

<template>
 <div class=”section”>
 <div class=”container”>
 <div class=”columns” style=’min-height:800px;’>
 <div class=”column is-6">
 <div class=”image is-2by2">
 <img src=”https://cdn.scotch.io/2842/b7yhhuUPSGO1fEkMHD6P_sticks.jpeg”>
 </div>
 </div>
 <div class=”column is-5 is-offset-1">
 <div class=”title is-2">Bundle of Sticks</div>
 <p class=”title is-3 has-text-muted”>$ 15</p>
 <hr>
 <br>
 <p>This bundle of sticks provides an earthy fragrance and aesthetic natural appeal. Your bundle of sticks will come with a personalized note. The perfect natural gift for any time of year!</p>
 <br>
 <br>
 <p class=’level’>
 <router-link to=”/order” class=”button is-large is-primary level-item has-text-centered”>Buy Now</router-link>
 </p>
 <br>
 </div>
 </div>
 </div>
 </div>
</template>
<script>
export default {}
</script>

Как видите, этот компонент представляет собой простой HTML-код со специальными классами Bulma для стилизации. Единственная часть этого файла, относящаяся к Vue, - это компонент «‹router-link› ‹/router-link›«. Это автоматически генерирует тег привязки и связывает маршрут с маршрутами, которые мы определили для vue-router в нашем файле * main.js *.

Когда пользователь нажимает кнопку «Заказать сейчас», он будет перенаправлен на страницу «Заказ», где он сможет заполнить свои данные и отправить свою информацию для обработки платежа.

Страница заказа

На странице заказа отображаются поля для контактных данных пользователя (имя и адрес электронной почты), информация о доставке, персонализированное примечание для набора палочек и поля для данных их кредитной карты. Кроме того, мы делаем проверки, чтобы убедиться, что поля кредитной карты заполнены правильно с помощью некоторых методов проверки формы Vue.js в методе `validate`.

./src/components/Order.vue (html-часть)

<template>
 <div class=’container’>
 <div class=’columns’>
 <div class=’column is-4'>
 <img src=”https://cdn.scotch.io/2842/b7yhhuUPSGO1fEkMHD6P_sticks.jpeg" alt=”A bundle of sticks”>
 </div>
 <div class=’column is-4'> 
 <div class=’field’>
 <label>Name</label>
 <div class=”control has-icons-left has-icons-right”>
 <input class=”input” type=”text” placeholder=”First and Last” v-model=’name’>
 <span class=”icon is-small is-left”>
 <i class=”fa fa-user”></i>
 </span>
 </div>
 </div>
 <div class=”field”>
 <label>Email</label>
 <div class=”control has-icons-left has-icons-right”>
 <input class=”input” type=”text” placeholder=”Email address” v-model=’email’>
 <span class=”icon is-small is-left”>
 <i class=”fa fa-envelope”></i>
 </span>
 </div>
 </div>
 <hr id=’left-line’>
 
 <div class=”field”>
 <label for=”card_number”>Card Number</label>
 <input id=”card_number” v-model=”card.number” type=”text” :class=”[‘is-danger’ ? cardNumberError : ‘’, ‘input’]” placeholder=’4242424242424242'>
 <span class=”help is-danger” v-show=”cardNumberError”>
 {{ cardNumberError }}
 </span>
 </div>
<div class=”field”>
 <label for=”cvc”>CVC</label>
 <input id=”cvc” v-model=”card.cvc” type=”text” class=”input” placeholder=’123'>
 <span class=”help is-danger” v-show=”cardCvcError”>
 {{ cardCvcError }}
 </span>
 </div>
<div class=”field”>
 <label for=”exp_month”>Expiry Month</label>
 
 <input id=”exp_month” v-model=”card.exp_month” type=”text” :class=”[‘is-danger’ ? cardMonthError : ‘’, ‘input’]” placeholder=”MM”>
 <span class=”help is-danger” v-show=”cardMonthError”>
 {{ cardMonthError }}
 </span>
 </div>
<div class=”field”>
 <label for=”exp_month”>Expiry Year</label>
 <input id=”exp_year” v-model=”card.exp_year” type=”text” :class=”[‘is-danger’ ? cardYearError : ‘’, ‘input’]” placeholder=”YY”>
 <span class=”help is-danger” v-show=”cardYearError”>
 {{ cardYearError }}
 </span>
 </div>
 
 <div class=”help is-danger” v-if=”cardCheckError”>
 <span>{{ cardCheckErrorMessage }}</span>
 </div> 
 </div>
 <div class=’column is-4'> 
 <label>Special Note</label>
 <textarea class=”textarea” placeholder=”What would you like the note to say?” v-model=’specialNote’></textarea>
 
 <hr>
 
 <div class=”field”>
 <label>Address</label>
 <input type=’text’ class=’input’ v-model=’address.street’ placeholder=’123 Fake St #303'>
 </div>
 <div class=”field”>
 <label>City</label>
 <input type=’text’ class=’input’ v-model=’address.city’ placeholder=’San Francisco’>
 </div>
 <div class=”field”>
 <label>State</label>
 <input type=’text’ class=’input’ v-model=’address.state’ placeholder=’CA’>
 </div>
 <div class=”field”>
 <label>Zip</label>
 <input type=’text’ class=’input’ v-model=’address.zip’ placeholder=’94607'>
 </div>
 </div>
 </div>
 <div class=”columns”>
 <div class=’column is-12'>
 <button type=”submit” class=”button is-primary is-large is-pulled-right” @click.prevent=”validate” :disabled=”cardCheckSending”>
 <span v-if=”cardCheckSending”>
 <i class=”fa fa-btn fa-spinner fa-spin”></i> 
 Ordering…
 </span>
 <span v-else>
 Place Order
 </span>
 </button>
 </div>
 </div>
 </div>
</template>
<style>
h2 { text-decoration: underline; }
.textarea:not([rows]) { max-height: 110px; min-height: 110px; }
.container { margin-bottom: 30px; }
.column > img { margin-top: 60px; }
.button-field { display: flex; justify-content: center; }
#left-line { margin-top:27px; }
</style>

Обновление: есть также компонент vue-stripe-elements, который может абстрагироваться от большей части этого кода, используя предварительно созданные Elements Stripe.

В приведенном выше коде шаблона мы стилизуем страницу и предоставляем изображение продукта, который покупатель собирается купить. Кроме того, мы привязываем ввод для этих полей формы с помощью v-model. Нам нужно будет определить эти поля в свойстве data объекта vue, показанном ниже. Мы также предоставляем вспомогательные классы, привязанные к определенным свойствам, чтобы отображать красные сообщения об ошибках, когда формы не заполнены должным образом или оставлены пустыми.

Логика Javascript для этого компонента находится в той же части и представлена ​​ниже. Этот код отвечает за привязку данных к полям формы, получение токена из Stripe и отправку платежного запроса на наш сервер Node.js.

./src/components/Order.vue (часть JS)

<script>
import axios from ‘axios’;
export default {
 data(){
  return {
   stripeKey: ‘YOUR_STRIPE_PUBLIC_KEY’,
// fields
   name: ‘Connor Leech’,
   email: ‘[email protected]’,
   specialNote: ‘This is the text to put on the bundle of sticks’,
   address: {
     street: ‘123 Something Lane’,
     city: ‘San Francisco’,
     state: ‘CA’,
     zip: ‘94607’
   },
   card: {
     number: ‘4242424242424242’,
     cvc: ‘123’,
     exp_month: ‘01’,
     exp_year: ‘19’
   },
   // validation
   cardNumberError: null,
   cardCvcError: null,
   cardMonthError: null,
   cardYearError: null,
   cardCheckSending: false,
   cardCheckError: false,
   cardCheckErrorMessage: ‘’
  }
 },
 methods: {
   validate(){
     this.clearCardErrors();
     let valid = true;
     if(!this.card.number){ valid = false; this.cardNumberError = “Card Number is Required”; }
     if(!this.card.cvc){ valid = false; this.cardCvcError = “CVC is Required”; }
     if(!this.card.exp_month){ valid = false; this.cardMonthError = “Month is Required”; }
     if(!this.card.exp_year){ valid = false; this.cardYearError = “Year is Required”; }
     if(valid){
       this.createToken();
     }
   },
   clearCardErrors(){
     this.cardNumberError = null;
     this.cardCvcError = null;
     this.cardMonthError = null;
     this.cardYearError = null;
   },
   createToken() {
     this.cardCheckError = false;
     window.Stripe.setPublishableKey(this.stripeKey);
     window.Stripe.createToken(this.card, $.proxy(this.stripeResponseHandler, this));
     this.cardCheckSending = true;
   },
   stripeResponseHandler(status, response) {
     this.cardCheckSending = false;
     if (response.error) {
       this.cardCheckErrorMessage = response.error.message;
       this.cardCheckError = true;
       console.error(response.error);
     } else {
       // token to create a charge on our server 
       var token_from_stripe = response.id;
       var request = {
         name: this.name,
         email: this.email,
         specialNote: this.specialNote,
         address: this.address,
         card: this.card,
         token_from_stripe: token_from_stripe
       };
       // Send to our server
       axios.post(`${window.endpoint}/charge`, request)
         .then((res) => {
           var error = res.data.error;
           var charge = res.data.charge;
           if (error){
             console.error(error);
           } else {
             this.$router.push({ path: `order-complete/${charge.id}` })
           }
       });
     }
   }
 }
}
</script>

Обновите еще раз: Оглядываясь назад на этот код, я бы, вероятно, переписал его, используя vue-stripe-elements. Первоначально у меня была проблема с его настройкой, но я объединил PR с некоторыми инструкциями по началу работы, чтобы все было кристально ясным.

Функция createToken () использует библиотеку Stripe.js для создания уникального токена для нашего конкретного запроса на оплату. Когда у нас есть этот токен, мы запускаем метод stripeResponseHandler. Это проверяет отсутствие ошибок и отправляет запрос на наш сервер для обработки. Если мы успешно произведем оплату на нашем сервере Node.js, используя токен, предоставленный нам Stripe.js, мы перенаправим пользователя на страницу завершения заказа. Здесь также есть дополнительная логика для отображения ошибок проверки.

Страница завершения заказа

И, наконец, мы попадаем на страницу завершения заказа. Эта страница будет отображена после того, как мы успешно создадим плату на нашем сервере. URL-адрес будет включать уникальный идентификатор, связанный с конкретным начислением, которое мы создали. Этот URL-адрес будет постоянным, поэтому пользователь сможет вернуться к нему в любое время, чтобы просмотреть сведения о своем заказе.

./src/components/Complete.vue

<template>
 <div class=’container content’>
 <br>
 <h3 style=’color: white;’>Order complete!</h3>
 <p>Congratulations! Your order for Sticks will be shipped out within 1–2 business days. <a href=’’>[email protected]</a>. We sent you a confirmation email for your records. Thanks so much!</p>
<div v-if=’orderDetails’>
 <dl>
 <dt>Order Number</dt>
 <dd>{{ orderDetails.id }}</dd>
 <dt>Order Created</dt>
 <dd>{{ orderDetails.created | moment }}</dd>
 <dt>Payment Amount</dt>
 <dd>{{ orderDetails.amount | currency }}</dd>
 <dt>Shipping Address</dt>
 <dd>{{ orderDetails.shipping.address.line1 }}, {{ orderDetails.shipping.address.city }}, {{ orderDetails.shipping.address.state }} {{ orderDetails.shipping.address.postal_code }}</dd>
 <dt>Engraving Text</dt>
 <dd>{{ orderDetails.description }}</dd>
 <dt>Email</dt>
 <dd>{{ orderDetails.receipt_email }}</dd>
 </dl>
 </div>
 </div>
</template>
<style>
 dt { font-weight: bold; }
</style>
<script>
import axios from ‘axios’;
import moment from ‘moment’;
export default {
 data(){
   return {
     orderDetails: false
   };
 },
 created(){
   var charge_id = this.$route.params.id;
   axios.get(`${window.endpoint}/charge/${charge_id}`)
      .then((res)=>{
         this.orderDetails = res.data.charge;
       });
 },
 filters: {
   moment(date) {
     return moment.unix(date).format(‘MMMM Do, YYYY — h:mm a’);
   },
   currency(amount){
     return `$${(amount/100).toFixed( 2 )}`;
   }
 }
}
</script>

В этом файле мы снова обращаемся к нашему бэкэнду, чтобы получить подробную информацию о заказе по идентификационному номеру в URL-адресе. Затем мы привязываем эти данные для отображения на экране с помощью Vue.js. Мы также определяем фильтры вывода моментов и валют, чтобы отформатировать, как валюта и даты отображаются на экране.

Тестирование внешнего интерфейса

В консоли запустите `npm run dev`, и внешняя страница нашего веб-сайта будет отображена на http: // localhost: 8080 / # / в новой вкладке. Вы должны увидеть следующие экраны для просмотра продукта и заполнения деталей заказа.

В следующем разделе мы настроим сервер Node.js для создания фактических сборов.

Давайте настроим сервер!

Бэкэнд-приложение

Наш сервер будет отвечать за взимание платы с пользователя и предоставление информации о заказе обратно клиенту. Мы собираемся создать новый каталог проекта, чтобы сохранить наше приложение Node.js. Это будет отдельный репозиторий кода от внешнего интерфейса и развернутый отдельно.

Сначала давайте создадим наш серверный проект Node.js и проверим проект в Git для контроля версий. Позже мы будем использовать git, чтобы развернуть наше приложение в Интернете с помощью Heroku.

$ mkdir stickly-backend
$ cd stickly-backend
$ npm init
$ touch server.js .env .gitignore
$ git init
$ git add -A
$ git commit -m ‘initial commit’

Это создаст пустой каркас для нашего проекта Node.js и проверит изменения в git для контроля версий. Убедитесь, что вы добавили файл `.gitignore`, который включает` .env`, чтобы вы случайно не отправили свои секретные ключи в Интернет. Этот файл выглядит так:

./.env

STRIPE_SECRET_KEY=sk_test_XXXXXXXXXXXXXXXXXXXXXXX

Нам нужно несколько пакетов npm. Эти пакеты будут добавлены в файл * package.json * благодаря флагу `- save`. Команда `npm init` создала наш файл * package.json *. Чтобы установить дополнительные пакеты Node.js с помощью npm run:

$ npm install express body-parser cors dotenv method-override stripe --save

Большинство из них являются вспомогательными пакетами, которые помогают веб-серверу Express Node.js принимать и обрабатывать входящие запросы из Интернета. Пакет Stripe предназначен для отправки и обработки платежей.

Мы собираемся определить наше приложение и маршруты в файле server.js следующим образом:

./server.js

// Grabs our environment variables from the .env file
require(‘dotenv’).config();
var express = require(‘express’),
 bodyParser = require(‘body-parser’),
 methodOverride = require(‘method-override’),
 cors = require(‘cors’),
 app = express();
// Environment configuration
var env = process.env.NODE_ENV = process.env.NODE_ENV || ‘development’;
var port = process.env.PORT || 3000;
// Create a server side router
var router = express.Router();
// Configure express to handle HTTP requests
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
 extended: true
})); 
app.use(methodOverride());
// Configure our Stripe secret key and object
var stripe = require(‘stripe’)(process.env.STRIPE_SECRET_KEY);
// Define the route endpoints for our application
// Create a new charge
router.post(‘/charge’, function(req, res){
 // Create the charge object with data from the Vue.js client
 var newCharge = {
   amount: 23500,
   currency: “usd”,
   source: req.body.token_from_stripe, // obtained with Stripe.js on the client side
   description: req.body.specialNote,
   receipt_email: req.body.email,
   shipping: {
     name: req.body.name,
     address: {
       line1: req.body.address.street,
       city: req.body.address.city,
       state: req.body.address.state,
       postal_code: req.body.address.zip,
       country: ‘US’
     }
   }
 };
 // Call the stripe objects helper functions to trigger a new charge
 stripe.charges.create(newCharge, function(err, charge) {
   // send response
   if (err){
     console.error(err);
     res.json({ error: err, charge: false });
   } else {
     // send response with charge data
     res.json({ error: false, charge: charge });
   }
 });
});
// Route to get the data for a charge filtered by the charge’s id
router.get(‘/charge/:id’, function(req, res){
 stripe.charges.retrieve(req.params.id, function(err, charge) {
   if (err){
     res.json({ error: err, charge: false });
   } else {
     res.json({ error: false, charge: charge });
   }
 });
});
// Register the router
app.use(‘/’, router);
// Start the server
app.listen(port, function(){
 console.log(‘Server listening on port ‘ + port)
});

Поздравляю! У нас есть приложение, настроенное в нашей локальной среде. Чтобы запустить приложение Vue, запустите `npm run dev` в командной строке. Откройте отдельное окно и запустите `node server`. Затем мы можем инициировать сборы и переходить на различные веб-страницы и переходить к конечным точкам URL. В следующем разделе мы собираемся развернуть эти приложения в Интернете.

Развертывание

Наше интерфейсное приложение будет размещено на Amazon S3. Наш сервер Node.js будет размещен на Heroku.

Разверните приложение Vue.js на S3

Во-первых, мы собираемся развернуть наш статический веб-сайт в Amazon Simple Storage Service (S3). Если вы не знакомы с S3, его также можно развернуть в других службах статического хостинга, таких как Github Pages или Netlify. S3 очень доступен по цене и имеет дополнительное преимущество в виде бесконечного масштабирования на тот случай, если МНОГО людей захотят купить флешки.

Зайдите в AWS Consle и выберите S3. Оказавшись там, выберите Создать сегмент.

Имя сегмента должно быть глобально уникальным, поэтому вы не сможете использовать то же имя сегмента, что и я. Поскольку на этом сервере будет размещаться наш код, мы хотим, чтобы он был общедоступным для всех. Выберите Предоставить общий доступ для чтения.

Создав сегмент, щелкните его и выберите Свойства, а затем перейдите в раздел Статический хостинг веб-сайтов. Это будет обслуживать наш файл index.html по уникальному URL-адресу сегмента.

Поздравляю! Вы создали корзину S3, в которой мы можем разместить наш веб-сайт. Чтобы создать наше приложение Vue.js для производства, зайдите в репозиторий внешнего интерфейса и запустите:

$ npm run build

Это создаст папку `dist` из наших связанных файлов Javascript, готовую к производству. Затем мы собираемся загрузить эту папку и index.html в нашу корзину S3. Перейдите в корзину и выберите Загрузить. Перетащите наше приложение Vue.js в корзину.

Нажмите Далее. На следующей странице выберите Предоставить общий доступ для чтения этим объектам. Все остальное можно оставить как есть.

Теперь, если вы перейдете на http://YOUR_BUCKET_NAME.s3-website-REGION.amazonaws.com/#/, вы сможете увидеть свой сайт в реальном времени в Интернете. Например, ссылка на мое ведро:

Http://stickly.io.s3-website-us-west-1.amazonaws.com/#/

Мы выберем лучшее доменное имя (необязательный шаг), но сначала давайте развернем наш сервер с помощью Heroku.

Разверните приложение Node.js в Heroku

Нам нужно добавить один файл под названием Procfile, который сообщает Heroku, как запустить наш сервер. Это выглядит так:

Procfile

web: node server.js

Зайдите в репозиторий на стороне сервера и обязательно установите интерфейс командной строки (CLI) heroku. Зарегистрируйте проект в git и создайте новое приложение heroku с помощью следующих команд:

$ git init 
$ git add -A
$ git commit -m ‘initial commit’
$ heroku create MY_APP_NAME

Мы также должны установить переменные среды напрямую с помощью Heroku. Выполните следующие дополнительные команды:

$ heroku config:set STRIPE_SECRET_KEY=sk_test_XXXXXXXXXXXXXXXXXXXXXXX

Чтобы развернуть наш сервер и просмотреть его в браузере, выполните:

$ git push heroku master
$ heroku open 

Наш бэкэнд работает! Теперь, когда вы переходите на живой веб-сайт, наше приложение Vue.js будет вызывать функции маршрутизации на нашем сервере Heroku. Убедитесь, что вы обновили конфигурацию среды src / main.js, указав свое имя приложения Heroku. Таким образом, при разработке мы будем делать запросы XHR (ajax) на localhost: 3000, но при производстве запросы будут отправляться на наш облачный сервер.

Чтобы принимать реальные деньги, вы можете обновить переменные среды Stripe с помощью своих производственных ключей.

Поздравляем, вы прошли этот урок! Вы можете просмотреть исходный код этих приложений ниже:

Спасибо за прочтение!

Изначально опубликовано в моем блоге