React 前端,Django 后端,Braintree API CORS 错误

问题描述 投票:0回答:0

你好几天来我一直在为这个问题而苦苦挣扎,我已经在 React 中构建了一个应用程序,后端使用的是 django 和 DRF,我正在使用 braintree 作为支付平台,我正在尝试从 React 中发布一个表单到 django 但在反应中我得到错误说获取失败因为它被 CORS 阻止,在 django 中我得到一个错误 400 说错误的请求,并且请求类型是 OPTIONS,我做了一些故障排除并证明表单是发送为空(我正在阅读有关 OPTIONS 的内容,似乎如果服务器不允许该请求,那么它就会变成一个空数组)。我已将 django-cors-headers 添加到已安装的应用程序、中间件、允许的主机等。无论如何,这是我的代码。

借记卡.js

import { useState, useEffect } from 'react';
import axios from 'axios';
import * as braintree from 'braintree-web'

function DebitCard() {
  const storedData = localStorage.getItem('donationData');
  const formData = storedData ? JSON.parse(storedData) : null;

  const [clientToken, setClientToken] = useState(null);
  const [client, setClient] = useState(null);
  const [hostedFieldsInstance, setHostedFieldsInstance] = useState(null)

  useEffect(() => {
    async function fetchClientToken() {
      try {
        const response = await fetch('http://127.0.0.1:3001/client-token/');
        const jsonResponse = await response.json();
        const clientToken = jsonResponse.client_token;
        setClientToken(clientToken);
      } catch (err) {
        console.error('Failed to fetch client token:', err);
      }
    }
  
    fetchClientToken();
  }, []);

  useEffect(() => {
    if (clientToken) {
      braintree.client
        .create({ authorization:clientToken })
        .then((clientInstance) => {
          setClient(clientInstance);
        })
        .catch((err) => {
          console.log('Failed to create client:', err)
        });
    }
  },[clientToken]);

  useEffect(()=> {
    if (client) {
      braintree.hostedFields
        .create({
          client: client,
          styles:{

          },
          fields:{
            number:{
              selector: '#card-number',
            },
            cvv:{
              selector: '#card-cvv',
            },
            expirationDate: {
              selector: '#card-expiry',
            },
            postalCode: {
              selector: '#zipcode',
            }
          }
        })
        .then((hostedFieldsInstance) => {
          setHostedFieldsInstance(hostedFieldsInstance)
        })
        .catch((err) => {
          console.log('Failed to created hosted fields', err)
        })
    }
  }, [client]);
  


  const handleSubmit = async (event) => {
    event.preventDefault();
  
    const transactionData = {
      first_name: formData.firstName,
      last_name: formData.lastName,
      email: formData.email,
      phone: formData.phone,
      amount: formData.donationAmount,
      program: formData.donationType,
      billing_address: '560 Lambert Rd',
      billing_city_town: 'Brea',
      billing_state: 'California',
    };
  
    if (hostedFieldsInstance) {
      try {
        const { nonce } = await hostedFieldsInstance.tokenize();
        transactionData['payment_method_nonce'] = nonce;
  
        const response = await axios.post('http://127.0.0.1:3001/mobile-booth-donation/', transactionData, {
          headers: {
            'Content-Type': 'application/json'
          }
        });
        
        console.log(response);
  
        if (!response.data.success) {
          throw new Error('Failed to submit transaction data');
        }
        
        console.log('Transaction data submitted successfully');
      } catch (err) {
        console.error('Failed to tokenize hosted fields', err);
      }
    }
  };



  return (
    <div className='debit-card-payment'>
    <form onSubmit={handleSubmit}>
      <div className='input-field'>
        <label htmlFor="card-number-label">Card Number:</label>
        <div id="card-number" placeholder="4444 4444 4444 4444" ></div>
      </div>
      <div className='exp-cvc-wrapper'>
      <div className='input-field'>
        <label htmlFor="card-expiry-label">Exp Date:</label>
        <div id="card-expiry" placeholder="12/24" ></div>
      </div>
        <div className='input-field'>
          <label htmlFor="card-cvv-label">CVC:</label>
          <div id="card-cvv" placeholder="123" ></div>
        </div>
        <div className='input-field'>
          <label htmlFor="zipcode-label">Zipcode:</label>
          <div id="zipcode" placeholder="123" ></div>
        </div>
      </div>
      <button type="submit">Pay with Debit Card</button>
    </form>
    </div>
  );
}

export default DebitCard;

Django API

gateway = braintree.BraintreeGateway(
            braintree.Configuration(
                braintree.Environment.Production,
                merchant_id=settings.BRAINTREE_MERCHANT_ID_PRODUCTION,
                public_key=settings.BRAINTREE_PUBLIC_KEY_PRODUCTION,
                private_key=settings.BRAINTREE_PRIVATE_KEY_PRODUCTION

@csrf_exempt
def braintree_token(request):
    gateway = braintree_gateway(request)
    client_token = gateway.client_token.generate()
    print("Generated client token:", client_token)
    response = JsonResponse({"client_token": client_token})
    response["Access-Control-Allow-Origin"] = "http://localhost:3000"
    return response

@method_decorator(csrf_exempt, name='dispatch')
class CheckoutFormView(FormView):
    print('executing')
    template_name = 'checkout.html'
    success_url = '/checkout/thank-you/'
    http_method_names = ['post', 'get','options']
    
    def options(self, request, *args, **kwargs):
        print(request.body)
        if request.body:
            try:
                print(request.body)
                print(json.loads(request.body))
            except json.JSONDecodeError as e:
                print(f"JSONDecodeError: {e}")
                return JsonResponse({"error": "Invalid JSON"}, status=400)
        else:
            print("Empty request body")
            return JsonResponse({"error": "Empty request body"}, status=400)

        response = HttpResponse()
        response['Access-Control-Allow-Origin'] = '*'
        response['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS'
        response['Access-Control-Allow-Headers'] = 'Content-Type'
        return response



    def get_form_class(self):
        print('checkout type')
        if self.request.session.get('checkout_type') == 'purchase':
            self.form_class = OrderForm
        elif self.request.session.get('checkout_type') == 'subscribe':
            self.form_class = SubscribeForm
        elif self.request.session.get('checkout_type') == 'registration':
            self.form_class = RegistrationForm
        else:
            self.form_class = DonateForm
        return self.form_class

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        try:
            program = self.request.session['program']
            program = Program.objects.get(slug=program.slug)
        except:
            program = Program.objects.get(slug='where-its-needed-most')
            
        context['product'] = self.request.session.get('product', '')
        context['event'] = self.request.session.get('event', '')
        context['schedule'] = self.request.session.get('schedule', '')
        context['checkout_type'] = self.request.session.get('checkout_type', 'donation')
        context['occurrence'] = self.request.session.get('occurrence', 'onetime')
        context['quantity'] = self.request.session.get('quantity', 1)
        context['notes'] = self.request.session.get('notes', '')
        context['special_instructions'] = self.request.session.get('special_instructions', '')
        context['program'] = program
        context['amount_1'] = self.request.session.get('amount', '50')
        context['amount_2'] = 150
        context['amount_3'] = 600
        context['amount_4'] = 1000
        context['programs'] = Program.objects.all()

        return context

    def get_initial(self):
        initial = super().get_initial()

        product = self.request.session.get('product', '')
        program = self.request.session.get('program', 'where-its-needed-most')
        schedule = self.request.session.get('schedule', '')
        shirt_size = self.request.session.get('shirt_size', '')

        if self.request.session.get('checkout_type') == 'purchase':
            initial["product"] = product
            initial["program"] = program
            initial['occurrence'] = 'onetime'
        elif self.request.session.get('checkout_type') == 'registration':
            initial["schedule"] = schedule
            initial["program"] = program
            initial["shirt_size"] = shirt_size
            initial['occurrence'] = 'onetime'
        elif 'rapid-response' in self.request.META.get('HTTP_REFERER', ''):
            initial['program'] = Program.objects.get(name="College Support")
        elif 'brandsource-scholars' in self.request.META.get('HTTP_REFERER', ''):
            initial['program'] = Program.objects.get(name="Scholarships")
        elif 'american-industries-scholarship' in self.request.META.get('HTTP_REFERER', ''):
            initial['program'] = Program.objects.get(name="Scholarships")
        else:
            initial['program'] = program

        initial['first_name'] = self.request.session.get('first_name', '')
        initial['last_name'] = self.request.session.get('last_name', '')
        initial['email'] = self.request.session.get('email', '')
        initial['phone'] = self.request.session.get('phone', '')
        initial['billing_address'] = self.request.session.get('billing_address', '')
        initial['billing_address_ext'] = self.request.session.get('billing_address_ext', '')
        initial['billing_city_town'] = self.request.session.get('billing_city_town', '')
        initial['billing_state'] = self.request.session.get('billing_state', '')
        initial['billing_zipcode'] = self.request.session.get('billing_zipcode', '')
        initial['checkout_type'] = self.request.session.get('checkout_type', 'donation')
        initial['occurrence'] = self.request.session.get('occurrence', 'onetime')
        initial['amount'] = self.request.session.get('amount', "50")
        initial['quantity'] = self.request.session.get('quantity', "1")
        initial['company_matching'] = "no"
        initial['notes'] = self.request.session.get('notes', '')
        initial['utm_campaign'] = self.request.COOKIES.get('utm_campaign', '')
        initial['utm_content'] = self.request.COOKIES.get('utm_content', '')
        initial['utm_source'] = self.request.COOKIES.get('utm_source', '')
        initial['utm_medium'] = self.request.COOKIES.get('utm_medium', '')
        initial['utm_date'] = self.request.COOKIES.get('utm_date', '')
        initial['special_instructions'] = self.request.session.get('special_instructions', '')
        initial['conversion_url'] = self.request.META.get("HTTP_REFERER", '').split("?")[0]

        return initial

    def post(self, request, *args, **kwargs):
        form = self.get_form()
        if form.is_valid():
            print('form valid')
            return self.form_valid(form)
        else:
            print('form invalid mate')
            print(form.errors)
            messages.error(request, "An unexpected error has occurred.")
            return self.form_invalid(form)

    def form_valid(self, form):
        gateway = braintree_gateway(self.request)
        customer = find_or_create_customer(gateway, form)
        if form.cleaned_data['occurrence'] == 'monthly' or form.cleaned_data['occurrence'] == 'annually' or form.cleaned_data['occurrence'] == 'biannually':
            result = braintree_process_recurring_payment(self, form, gateway, customer)
            print(result)
        else:
            result = braintree_process_onetime_payment(self, form, gateway, customer)
            print(result)
        if result.is_success:            
            return super().form_valid(form)
        else:
            html_content_internal = render_to_string('emails/donation_error.html', { 
                'message': result.message,
                'params': result.params,
                }
            )  

            subject, from_email, to = 'Donation Failure', 'Foster Love <[email protected]>', "[email protected]"
            text_content = 'Payment Received'
            msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
            msg.attach_alternative(html_content_internal, "text/html")
            msg.send()
            messages.error(self.request, result.message)
            print(result)
            return super().form_invalid(form)

def find_or_create_customer(gateway, form):

    first_name = form.cleaned_data["first_name"]
    last_name = form.cleaned_data["last_name"]
    email = form.cleaned_data["email"]
    phone = form.cleaned_data["phone"]
    group_type = form.cleaned_data["group_type"]
    billing_address = form.cleaned_data["billing_address"]
    billing_address_ext = form.cleaned_data["billing_address_ext"]
    billing_city_town = form.cleaned_data["billing_city_town"]
    billing_state = form.cleaned_data["billing_state"]
    billing_zipcode = form.cleaned_data["billing_zipcode"]

    try:
        customer = Customer.objects.get(email=email)
        customer = gateway.customer.find(customer.braintree_id)
        customer_id = customer.id
    except:
        try:
            customer = gateway.customer.find(customer.braintree_id)
            customer_id = customer.id
        except:
            result = gateway.customer.create({
                "first_name": first_name,
                "last_name": last_name,
                "phone": re.sub('[^0-9]', '', phone),
                "email": email,
            })
            if result.is_success:
                customer_id = result.customer.id
            else:
                customer_id = uuid.uuid4()

    values_to_update = {
        'first_name': first_name,
        'last_name': last_name,
        'phone': re.sub('[^0-9]', '', phone),
        'group_type': group_type,
        'billing_address': billing_address,
        'billing_address_ext': billing_address_ext,
        'billing_city_town': billing_city_town,
        'billing_state': billing_state,
        'billing_zipcode': billing_zipcode,
        'braintree_id': customer_id,
        'zoho_contact_id': create_or_update_zoho_contact(first_name, last_name, email, phone, group_type, billing_address, billing_address_ext, billing_city_town, billing_state, billing_zipcode)
    }

    customer, created = Customer.objects.update_or_create(
        email = email,
        defaults=values_to_update
    )
    customer.save()

    return customer
reactjs django cors braintree
© www.soinside.com 2019 - 2024. All rights reserved.