简体   繁体   中英

Why is Axios not including XSRF-TOKEN when POSTing from React sub-component?

I have a Laravel 6.x app that I'm working on. Axios seems to not be consistent about when it sends XSRF-TOKEN headers.

Then I have two pages within the app that need to do axios posts. One of which works correctly, the other - which does the actual post from a Component included within a Component - excludes the header and fails.

The common files are

js/app.js

require('./bootstrap');

js/bootstrap.js

window.axios = require('axios');
//snip
let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}

layouts/reactapp.blade.php

<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
    <meta name="csrf-token" content="{{ csrf_token() }}">
</head>
<body>
    @yield('reactContainer')
    <script src="{{ asset('js/app.js') }}"></script>
    @yield('components')
</body>
</html>

The working page is orders/create.blade.php

@extends('layouts.reactapp')

@section('reactContainer')
    <div id='orders-create'></div>
@endsection

@section('components')
    <script src="{{ asset('js/components/Orders.js') }}"></script>
@endsection

js/components/Orders.js

import React, { Component } from 'react';
import {Page} from '@shopify/polaris';
import ReactDOM from 'react-dom';

export default class Orders extends Component {
    constructor(props) {
        super(props);
        this.onFormSubmit = this.onFormSubmit.bind(this);
        this.handleFileUpload = this.handleFileUpload.bind(this);
    }
    render() {
        return (
            <Page
                title="Orders"
                primaryAction={{
                    content: 'Submit',
                    onAction: this.onFormSubmit,
                }}
            ><!-- snip --></Page>
        );
    }
    onFormSubmit() {
        this.handleFileUpload().then((response) => { /*snip*/ });
    }
    handleFileUpload() {
        return window.axios.post(url, formData, config);
    }
};
if (document.getElementById('orders-create')) {
    ReactDOM.render(<Orders />, document.getElementById('orders-create'));
}

The non-working page is shopify/settings.blade.php

@extends('layouts.reactapp')

@section('reactContainer')
    <div id='shopify-setting'></div>
@endsection

@section('components')
    <script src="{{ asset('js/components/Setting.js') }}"></script>
@endsection

js/components/Setting.js

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import SettingCheckbox from './fields/SettingCheckbox.js';
export default class Setting extends Component {
    render() {
        return (
            return <SettingCheckbox
                setting={setting}
                key={setting.id}
            />
        );
    }
}
if (document.getElementById('shopify-setting')) {
    ReactDOM.render(<Setting />, document.getElementById('shopify-setting'));
}

js/component/SettingCheckbox.js

import { Button } from '@shopify/polaris';
import React, { Component } from 'react';

export default class SettingCheckbox extends Component {
    constructor(props) {
        super(props);
        this.updateSetting = this.updateSetting.bind(this);
    }
    render() {
        return(
            <Button onclick={this.updateSetting}>Update</Button>
        );
    }
    updateSetting() {
        window.axios.patch(url, formData).then(/*snip*/);
    }
}

I don't see any critical difference between these two. It should be the same axios object either way, why would it behave any differently in a nested component?

I don't know how correct a solution this is, but setting axios.withCredentials globally ultimately did it.

js/bootstrap.js

window.axios = require('axios');
window.axios.defaults.withCredentials = true;
//snip
let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}

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