简体   繁体   中英

Vue.js-Failed to load resource: the server responded with a status of 401 (Unauthorized)

I'm currently working on a project that collects payment info(like the products the client wants to buy, and how much that product costs) and client details(client name, client address, client credit card info, etc.) and I need to access Stripe's online payment system for the purchase. However, during my trial run, every time I try to click all "Pay", I keep getting notifications that something went wrong. I checked the terminal and it keeps displaying this error:

Failed to load resource: the server responded with a status of 401 (Unauthorized)

I'm also using Django's rest framework for my backend development, and it keeps displaying this

 HTTP 401 Unauthorized
    Allow: POST, OPTIONS
    Content-Type: application/json
    Vary: Accept
    WWW-Authenticate: Token
    
    {
        "detail": "Authentication credentials were not provided."
    }

This is the code I think the problem is located in:

<template>
  <div class="page-checkout">
    <div class="columns is-multiline">
      <div class="column is-12">
        <h1 class="title">Checkout</h1>
      </div>

      <div class="column is-12 box">
        <table class="table is-fullwidth">
          <thead>
            <tr>
              <th>Product</th>
              <th>Price</th>
              <th>Quantity</th>
              <th>Total</th>
            </tr>
          </thead>

          <tbody>
            <tr v-for="item in cart.items" v-bind:key="item.product.id">
              <td>{{ item.product.name }}</td>
              <td>{{ item.product.price }}</td>
              <td>{{ item.quantity }}</td>
              <td>₱{{ getItemTotal(item).toFixed(2) }}</td>
            </tr>
          </tbody>

          <tfoot>
            <tr>
              <td colspan="2">Total</td>
              <td>{{ cartTotalLength }}</td>
              <td>₱{{ cartTotalPrice.toFixed(2) }}</td>
            </tr>
          </tfoot>
        </table>
      </div>

      <div class="column is-12 box">
        <h2 class="subtitle">Shipping Details</h2>

        <p class="has-text-grey mb-4">* All fields required</p>

        <div class="columns is-multiline">
          <div class="column is-6">
            <div class="field">
              <label>First Name*</label>
              <div class="control">
                <input type="text" class="input" v-model="first_name">
              </div>
            </div>

            <div class="field">
              <label>Last Name*</label>
              <div class="control">
                <input type="text" class="input" v-model="last_name">
              </div>
            </div>

            <div class="field">
              <label>E-mail*</label>
              <div class="control">
                <input type="email" class="input" v-model="email">
              </div>
            </div>

            <div class="field">
              <label>Phone*</label>
              <div class="control">
                <input type="text" class="input" v-model="phone">
              </div>
            </div>
          </div>

          <div class="column is-6">
            <div class="field">
              <label>Address*</label>
              <div class="control">
                <input type="text" class="input" v-model="address">
              </div>
            </div>

            <div class="field">
              <label>Zipcode*</label>
              <div class="control">
                <input type="text" class="input" v-model="zipcode">
              </div>
            </div>

            <div class="field">
              <label>Place*</label>
              <div class="control">
                <input type="email" class="input" v-model="place">
              </div>
            </div>
          </div>
        </div>

        <div class="notification is-danger mt-4" v-if="errors.length">
          <p v-for="error in errors" v-bind:key="error">{{ error }}</p>
        </div>

        <hr>

        <div id="card-element" class="mb-5"></div>

        <template v-if="cartTotalLength">
          <hr>

          <button class="button is-dark" @click="submitForm">Pay with Stripe</button>
        </template>
      </div>
    </div>
  </div>
</template>

<script>
import axios from 'axios'

export default {
  name: "Checkout",
  data() {
    return {
      cart: {
        items: []
      },
      stripe: {},
      card: {},
      first_name: '',
      last_name: '',
      email: '',
      phone: '',
      address: '',
      zipcode: '',
      place: '',
      errors: []
    }
  },
  mounted() {
    document.title = ' The "GO BUY IT" page | Bjackets '

    this.cart = this.$store.state.cart

    if (this.cartTotalLength > 0) {
      this.stripe = Stripe('pk_test_51L3bhzFMIo7cZ677WbW384hMgVFcLs9E0x4sLocwajtGbnZIlplXoWSlSKr1IM89tWOCFYIBOWPpcF8OzBWGCnZR00MN1fPAGW')
      const elements = this.stripe.elements();
      this.card = elements.create('card', { hidePostalCode: true })

      this.card.mount('#card-element')
    }
  },
  methods: {
    getItemTotal(item) {
      return item.quantity * item.product.price
    },
    submitForm() {
      this.errors = []

      if (this.first_name === '') {
        this.errors.push('The First Name feild is empty. Please fill-out the space with your first name. For example, "Gaylord"')
      }

      if (this.last_name === '') {
        this.errors.push('The Last Name feild is empty. Please fill-out the space with your last name. For example, "Gaylord"')
      }

      if (this.email === '') {
        this.errors.push('The email feild is missing. Please fill-out the space with your email. For example, "ThisExample@gmail.com"')
      }

      if (this.phone === '') {
        this.errors.push('The phone feild is missing. Please fill-out the space with your contact number. For example, "123-456-7890"')
      }

      if (this.address === '') {
        this.errors.push('The address feild is missing. Please fill-out the space with your address. In other words, tell me where you live.')
      }

      if (this.zipcode === '') {
        this.errors.push('The zipcode feild is missing.')
      }

      if (this.place === '') {
        this.errors.push('Are you located in Lozun, Visayas, Mindanao?')
      }

      if (!this.errors.length) {
        this.$store.commit('setIsLoading', true)

        this.stripe.createToken(this.card).then(result => {
          if (result.error) {
            this.$store.commit('setIsLoading', false)

            this.errors.push('Something went wrong with Stripe. Please try again')

            console.log(result.error.message)
          } else {
            this.stripeTokenHandler(result.token)
          }
        })
      }
    },
    async stripeTokenHandler(token) {
      const items = []

      for (let i = 0; i < this.cart.items.length; i++) {
        const item = this.cart.items[i]
        const obj = {
          product: item.product.id,
          quantity: item.quantity,
          price: item.product.price * item.quantity
        }

        items.push(obj)
      }

      const data = {
        'first_name': this.first_name,
        'last_name': this.last_name,
        'email': this.email,
        'address': this.address,
        'zipcode': this.zipcode,
        'place': this.place,
        'phone': this.phone,
        'items': items,
        'stripe_token': token.id
      }

      await axios
        .post('/api/v1/checkout/', data)
        .then(response => {
          this.$store.commit('clearCart')
          this.$router.push('/cart/success')
        })
        .catch(error => {
          this.errors.push('Something went wrong. Please try again')
          console.log(error)
        })
      this.$store.commit('setIsLoading', false)
    }
  },
  computed: {
    cartTotalPrice() {
      return this.cart.items.reduce((acc, curVal) => {
        return acc += curVal.product.price * curVal.quantity
      }, 0)
    },
    cartTotalLength() {
      return this.cart.items.reduce((acc, curVal) => {
        return acc += curVal.quantity
      }, 0)
    },
  }
}
</script>

This is the mani module that connects the orders from the client to the server(views.py),

import stripe

from django.conf import settings
from django.contrib.auth.models import User
from django.http import Http404
from django.shortcuts import render

from rest_framework import status, authentication, permissions
from rest_framework.decorators import api_view, authentication_classes, permission_classes
from rest_framework.views import APIView
from rest_framework.response import Response

from .models import Order, OrderItem
from .serializers import OrderSerializer

@api_view(['POST'])
@authentication_classes([authentication.TokenAuthentication])
@permission_classes([permissions.IsAuthenticated])

def checkout(request):
  serializer = OrderSerializer(data=request.POST)

  if serializer.is_valid():
    stripe.api_key = settings.STRIPE_SECRET_KEY
    paid_amount = sum(item.get('quantity') * item.get('product').price for item in serializer.validated_data['items'])

    try:
      charge = stripe.Charge.create(
        amount=int(paid_amount * 100),
        currency='USD',
        description='Charge from Bjackets',
        source=serializer.validated_data['stripe_token']
      )

      serializer.save(user=request.user, paid_amount=paid_amount)

      return Response(serializer.data, status=status.HTTP_201_CREATED)
    except Exception:
      return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

  return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)  

I think you set the API permission as IsAuthenticated , but you didn't set the authentication header in the frontend.

Please add the authentication header or set the permission_classes as [permissions.AllowAny] in the api view.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM