React + Laravel 5.8.33 +Axios: ошибки при регистрации пользователя с помощью запроса axios.post; прояснение проблемы кода

Обновление

Проверка моей вкладки сети в моих инструментах разработки Firefox дает мне следующее:

Response headers (290 B)    
Raw headers
Access-Control-Allow-Origin 
*
Allow   
POST
Cache-Control   
no-cache, private
Connection  
close
Content-Type    
text/html; charset=UTF-8
Date    
Sat, 31 Aug 2019 09:45:04 GMT
Date    
Sat, 31 Aug 2019 09:45:04 GMT
Host    
localhost:8000
X-Powered-By    
PHP/7.2.19-0ubuntu0.18.04.2
Request headers (438 B) 
Raw headers
* Accept: */* *
Accept-Encoding 
gzip, deflate
Accept-Language 
en-US,en;q=0.5
Access-Control-Request-Headers  
x-csrf-token,x-requested-with,x-xsrf-token
Access-Control-Request-Method   
POST
Connection  
keep-alive
Host    
localhost:8000
Origin  
http://127.0.0.1:8000
Referer 
http://127.0.0.1:8000/register
User-Agent  
Mozilla/5.0 (X11; Ubuntu; Linu…) Gecko/20100101 Firefox/68.0

Почему метод GET? Попытка изменить это из инструментов, это дает, что метод POST не разрешен. Кроме того, при отправке запроса он предоставляет следующую информацию:

Обновление

Я начал вносить изменения в файл bootstrap.js, где требуется мой axios, но у меня ничего не получилось. Я пытался изменить

window.axios = require('axios');

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
от

до

window.axios = require('axios');

window.axios.defaults.headers.common = {
    'X-Requested-With': 'XMLHttpRequest',
    'X-CSRF-TOKEN' : document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
};

но на самом деле, я не могу добраться до точки. Я не могу понять, как работал связанный учебник в моих комментариях, и у меня начинает возникать нехватка идей о том, что искать. Итак, любая помощь приветствуется; если кто-то может указать на действительную ссылку, которая говорит: "Послушайте, это нерешенная проблема, тогда я реализую проект py с другим кодом; но если нет, то эта проблема не должна оставаться нерешенной. Если это небольшая ошибка с моей стороны, то где именно это? Спасибо всем.

Примечание: в моих исходных сообщениях я не показывал, как выглядят мои веб-маршруты. Так как я использую React изнутри Laravel (я использовал в пресете php artisan Terminal Preset;) мои веб-маршруты шли из предварительно настроенного кода laravel

Route::get('/', function () {
    return view('welcome');
});

к новому коду, который вызывает приложение React:

Route::view('/{path?}', 'app');

Update3: я пытался (со вчерашнего дня) изменить свой apache2 conf, и моя проблема остается. Я не знаю, следует ли это воспринимать как изменение:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8000/api/user/register. (Reason: missing token ‘x-requested-with in CORS header ‘Access-Control-Allow-Headers from CORS preflight channel).

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8000/api/user/register. (Reason: CORS request did not succeed).

Source map error: request failed with status 404
Resource URL: http://127.0.0.1:8002/js/app.js
Source Map URL: popper.js.map

Update2: я попытался изменить свой пост-запрос axios:

const dataofuser={
    name:data.name,
    email:data.email,
    password:data.password
}


 const instance = axios.create({
     method:'post',
     baseURL: 'http://localhost:8000/api/user/',
     timeout: 1000,
     headers: {'Access-Control-Allow-Origin': '*' , 'Access-Control-Allow-Methods ':  'POST, GET, OPTIONS, PUT, DELETE','Access-Control-Allow-Headers':  'Content-Type, X-Auth-Token, Origin, Authorization','X-Requested-With': 'XMLHttpRequest' }
 });

instance          .post("register/create",dataofuser)
           .then(response => {
            console.log(response);
            return response;
          })
           .then(json => {
            if (json.data.success) {
              alert('Registration Successful!');
              history.push('/')

... Но тогда я получаю

неверное имя заголовка


Оригинал Как я уже упоминал ранее в другом посте, в настоящее время я сам изучаю React и Laravel. Я пытаюсь создать базовое приложение для регистрации с React в качестве внешнего интерфейса и Laravel в качестве внутреннего. Это сообщение об ошибках, возникающих, когда я заполняю регистрационную форму и пытаюсь отправить ее; пользователь не регистрируется, и я получаю несколько ошибок в зависимости от того, что я пытаюсь.

Если я попробую:

axios
          .post("http://localhost:8000/api/user/register", {
              name: data.name,
              email: data.email,
              password: data.password
          })

Я попадаю в консоль:

> Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8000/api/user/register. (Reason: CORS header ‘Access-Control-Allow-Origin missing).

>Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8000/api/user/register. (Reason: CORS request did not succeed).

>Source map error: request failed with status 404
Resource URL: http://127.0.0.1:8000/js/app.js
Source Map URL: popper.js.map

>[object Object] Error: Network Error 

Если я попытаюсь

axios
  .post("/user/register", {
      name: data.name,
      email: data.email,
      password: data.password
  })

затем я получаю (я считаю, что это ошибка в отношении неверного определения маршрута):

Source map error: request failed with status 404
Resource URL: http://127.0.0.1:8000/js/app.js
Source Map URL: popper.js.map

Если я использую

axios
  .post("/api/user/register", {
      name: data.name,
      email: data.email,
      password: data.password
  })

я получаю:

Source map error: request failed with status 404
Resource URL: http://127.0.0.1:8000/js/app.js
Source Map URL: popper.js.map

[object Object] Error: Request failed with status code 500

Я больше не уверен (я не могу уточнить), если у меня есть проблема с CORS (хотя я предпринял действия, которые должны предотвратить такие проблемы) или какая-либо другая, маршрутизация или передача данных или просто синтаксическая проблема. Я бы решил проблему с CORS (хотя я понятия не имею, что это за уведомление popper.js.map). Я публикую код ниже.


Update1:

Я только что запустил свой код в браузере Chrome с помощью

 axios
          .post("http://localhost:8000/api/user/register", {
              name: data.name,
              email: data.email,
              password: data.password
          })

и я получил

Access to XMLHttpRequest at 'http://localhost:8000/api/user/register' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request does not pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
app.js:70270 [object Object] Error: Network Error
app.js:371 POST http://localhost:8000/api/user/register net::ERR_FAILED

Кажется, у меня проблема с CORS... и я не могу понять вчера и весь день сегодня, как ее решить.


Некоторый код:

Мой компонент App (родительский) содержит функцию, которая передается компоненту Register (дочерний); эта функция обрабатывает процесс регистрации

        import React, {Component} from 'react'
        import ReactDOM from 'react-dom'
        import {BrowserRouter, Route, Switch } from 'react-router-dom'
        // import {Link} from 'react-router-dom'
        import Header from './Header'
        import Intro from './Intro'
        import Register from './Register'
        import Login from './Login'
        import Userpage from './Userpage'
        import Footer from './Footer'
        import Science from './Science'
        import Literature from './Literature'
        // import {AppState} from 'react-native'


        class App extends Component {

            constructor(props){
                super(props);
                this.state={
                    isLoggedIn:false,
                    user:{},
                    data_user:'',
                    data_username:''
                }

                this.username_Callback=this.username_Callback.bind(this)
                this._registerUser=this._registerUser.bind(this)



            }

            componentDidMount() {
                let state = localStorage["appState"];
                if (state) {
                  let AppState = JSON.parse(state);
                  console.log(AppState);
                  this.setState({ isLoggedIn: AppState.isLoggedIn, user: AppState });
                }
          }

            _registerUser(data){

                $("#email-login-btn")
                  .attr("disabled", "disabled")
                  .html(
                    '<i class="fa fa-spinner fa-spin fa-1x fa-fw"></i><span class="sr-only">Loading...</span>'
                  );



                // var formData = new FormData(); 
                // formData.append('data.name');
                // formData.append('data.email');
                // formData.append('data.password');

                console.log(data)
                console.log(data.name)
                console.log(data.email)
                console.log(data.password)
                // console.log(formData)



                axios
                  .post("http://localhost:8000/api/user/register", {
                      name: data.name,
                      email: data.email,
                      password: data.password
                  })
                  .then(response => {
                    console.log(response);
                    return response;
                  })
                  .then(json => {
                    if (json.data.success) {
                      alert('Registration Successful!');
                      history.push('/')


                      let userData = {
                        name: json.data.data.name,
                        id: json.data.data.id,
                        email: json.data.data.email,
                        auth_token: json.data.data.auth_token,
                        timestamp: new Date().toString()
                      };
                      let appState = {
                        isLoggedIn: true,
                        user: userData
                      };
                      // save app state with user date in local storage
                      localStorage["appState"] = JSON.stringify(appState);
                      this.setState({
                        isLoggedIn: appState.isLoggedIn,
                        user: appState.user
                      });
                    } else {
                      alert('Registration Failed!');
                      $("#email-login-btn")
                        .removeAttr("disabled")
                        .html("Register");
                    }
                  })
                  .catch(error => {
                    alert("An Error Occured!" + error);
                    console.log('${data} ${error}');
                    $("#email-login-btn")
                      .removeAttr("disabled")
                      .html("Register");
                  });

          };



render(){
                return(


                    <BrowserRouter>

                        <Header listNameFromParent={this.state.data_username} />

                        <Footer />

                        <Switch>
                            <Route exact path='/' component={Intro} />
                            <Route path='/register' render={props=><Register {...props} registerUser={this._registerUser}/>}/>

                            <Route path='/login' render={props=><Login {...props} loginUser={this._loginUser}/>}/>
                            <Route path='/userpage' component={Userpage}/>
                            <Route path='/science' component={Science}/>
                            <Route path='/literature' component={Literature}/>

                        </Switch>


                    </BrowserRouter>




                    )
            }
        }

        ReactDOM.render(<App />, document.getElementById('app'))

Компонент My Register просто содержит форму и возвращает входные данные. Используя команду console.log, я проверяю, что данные действительно доступны в моем приложении и в моей функции регистрации. Если будет предложено, я могу опубликовать код.

На моем бэкэнде у меня есть:

api.php

<?php

        use Illuminate\Http\Request;

        // header('Access-Control-Allow-Origin: *');
        // //Access-Control-Allow-Origin: *
        // header('Access-Control-Allow-Methods:  POST, GET, OPTIONS, PUT, DELETE');
        // header('Access-Control-Allow-Headers:  Content-Type, X-Auth-Token, Origin, Authorization');
        /*
        |--------------------------------------------------------------------------
        | API Routes
        |--------------------------------------------------------------------------
        |
        | Here is where you can register API routes for your application. These
        | routes are loaded by the RouteServiceProvider within a group which
        | is assigned the "api" middleware group. Enjoy building your API!
        |
        */

        Route::middleware('auth:api')->get('/user', function (Request $request) {
            return $request->user();
        });


        Route::group(['middleware' => ['jwt.auth','api-header']], function () {

            // all routes to protected resources are registered here  
            Route::get('users/list', function(){
                $users = App\User::all();

                $response = ['success'=>true, 'data'=>$users];
                return response()->json($response, 201);
            });
        });
        Route::group(['middleware' => 'api-header'], function () {

            // The registration and login requests does not come with tokens 
            // as users at that point have not been authenticated yet
            // Therefore the jwtMiddleware will be exclusive of them
            Route::post('/user/login', '[email protected]');
            Route::post('/user/register', '[email protected]');
        });

API.php (промежуточный)

<?php

        namespace App\Http\Middleware;

        use Closure;

        class API
        {
            /**
             * Handle an incoming request.
             *
             * @param  \Illuminate\Http\Request  $request
             * @param  \Closure  $next
             * @return mixed
             */
            public function handle($request, Closure $next)
            {
                $response = $next($request);
                $response->header('Access-Control-Allow-Headers', 'Origin, Content-Type, Content-Range, Content-Disposition, Content-Description, X-Auth-Token');
                $response->header('Access-Control-Allow-Origin','*');
                $response->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
                $response->header('Access-Control-Allow-Headers',' Origin, Content-Type, Accept, Authorization, X-Request-With');
                $response->header('Access-Control-Allow-Credentials',' true');
                //add more headers here
                return $response;
            }
        }

UserController

<?php

    namespace App\Http\Controllers;

    use Illuminate\Http\Request;
    use App\User;
    use JWTAuth;
    use JWTAuthException;


    class UserController extends Controller
    {
        private function getToken($email, $password)
        {
            $token = null;
            //$credentials = $request->only('email', 'password');
            try {
                if (!$token = JWTAuth::attempt( ['email'=>$email, 'password'=>$password])) {
                    return response()->json([
                        'response' => 'error',
                        'message' => 'Password or email is invalid',
                        'token'=>$token
                    ]);
                }
            } catch (JWTAuthException $e) {
                return response()->json([
                    'response' => 'error',
                    'message' => 'Token creation failed',
                ]);
            }
            return $token;
        }
public function register(Request $request)
        { 


            $validator = Validator::make($request->all(), [
                'name' => 'required|max:255',
                'email' => 'required',
                'password' => 'required'
            ]);
            if ($validator->fails()) {
                return response()->json(['errors'=>$validator->errors()],422);
            }





            $payload = [
                'password'=>\Hash::make($request->password),
                'email'=>$request->email,
                'name'=>$request->name,
                'auth_token'=> ''
            ];




            $user = new \App\User($payload);
            if ($user->save())
            {

                $token = self::getToken($request->email, $request->password); // generate user token

                if (!is_string($token))  return response()->json(['success'=>false,'data'=>'Token generation failed'], 201);

                $user = \App\User::where('email', $request->email)->get()->first();

                $user->auth_token = $token; // update user token

                $user->save();

                $response = ['success'=>true, 'data'=>['name'=>$user->name,'id'=>$user->id,'email'=>$request->email,'auth_token'=>$token]];        
            }
            else
                $response = ['success'=>false, 'data'=>'Couldnt register user'];


            return response()->json($response, 201);
        }
    }

Итак, еще раз, я не могу уточнить, в чем конкретно проблема, и процедура регистрации не работает.

Ответы

Ответ 1

Если вы работаете с rest API, вам нужно позаботиться о CORS.

CORS - это в основном функция безопасности браузера, а не серверная часть.

По умолчанию браузер НЕ разрешает определенные запросы перекрестного происхождения. Сервер, с которым вы разговариваете, может публиковать информацию о том, безопасно ли использовать запросы из разных источников, но это клиент, который понимает и использует эту информацию и, следовательно, обеспечивает защиту, а не сервер.

Браузер автоматически отправляет HTTP-запрос перед исходным методом OPTIONS, чтобы проверить, безопасно ли отправлять исходный запрос.

Просто вам нужно включить CORS на стороне сервера, попробовав пакет laravel-cors или laravel-cors, который позволяет отправлять заголовки Cross-Origin Resource Sharing с конфигурацией промежуточного программного обеспечения Laravel.

ИЛИ альтернативным способом вы можете добавить строки ниже в заголовке laravel.

'Access-Control-Allow-Methods': 'POST, GET, PUT, OPTIONS, DELETE'
'Access-Control-Allow-Origin': '*'
'Access-Control-Allow-Credentials': ' true'

Ответ 2

Предварительные запросы - это запрос HTTP-OPTIONS, отправленный клиентом на сервер, чтобы убедиться, что он поддерживает протокол CORS.

https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request

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

Route::options('/{path}', function() {
  return response('', 200)
      ->header(
        'Access-Control-Allow-Headers', 
        'Origin, Content-Type, Content-Range, Content-Disposition, Content-Description, X-Auth-Token, X-Requested-With')
      ->header('Access-Control-Allow-Methods', 'POST, GET, PUT, OPTIONS, DELETE')
      ->header('Access-Control-Allow-Origin','*')
      ->header('Access-Control-Allow-Credentials',' true');
})->where('path', '.*');

Это похоже на подход промежуточного программного обеспечения в вашем вопросе, за исключением того, что промежуточное программное обеспечение подключено к маршрутам, но не предоставляет запасной вариант для запроса options к этим маршрутам.

Ответ 3

Я опубликую здесь, как я выяснил, что происходит с моим простым, но все же регистрационным приложением Laravel-React-Axios. Из вышеупомянутых постов, которые пытались решить проблему, только некоторые комментарии ClueMediator были полезны для понимания проблемы за кулисами и некоторые информативно-полезные комментарии Квентина на мой пост. Здесь я должен отметить, что, насколько я видел, все остальные посты и обсуждения на github об axios, laravel и .js front-end вообще не фокусировались на этом (или, если они это сделали, они делали это без любое серьезное внимание к нему).

Во-первых, в моем первом посте видно, что изменение запроса post с localhost: 8000 на просто имя API/маршрута, казалось, повлияло на удаление некоторых из cors; Поскольку я запускал проект на одном или двух серверах одновременно, cors мог возвращаться в зависимости от того, где ремесленник обслуживал приложение.

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

К точке. Кажется, что axios всегда пытается отправить вместе с запросом, который у меня был в моем коде (в данном примере запрос на публикацию), запрос опций. Что я сделал, чтобы проверить проблему, так это изменить свой хост и порт, пока ремесленник обслуживал, и собрать вместе мой код для правильного соответствия маршруту. Затем, проверив вкладку сети на консоли, я увидел, что хотя отправка запроса прошла нормально, у меня все еще были cors, потому что запрос axios.options по умолчанию шел на localhost: 8000, но я не обслуживал свое приложение оттуда, Задание ремесленника для обслуживания оттуда и исправление конструкции миграции решило проблему.

Здесь важно кое-что подчеркнуть: artisan обслуживает localhost: 8000 при первом его открытии/но при открытии второго сервера он переходит на следующий доступный порт, как обычно. Если бы не ошибки в коде миграции, я бы, наверное, понял проблему, возникшую у ремесленника и где он обслуживал. Но, из-за неправильной работы с моей базой данных, даже тогда я получал ошибку 500 как внутреннюю ошибку сервера, из-за которой я открыл другой сервер, а затем обнаружил, что axios всегда отправляет запрос опций только на localhost: даже 8000 если мой фронтенд и бэкэнд согласились друг с другом, многие изменения в коде приводили к несоответствиям. Итак, в заключение, после работы с плохим кодом (что-то, что я должен был увидеть быстрее, чем я), нужно было лишь правильно настроить аксиумы и ремесленников на согласование.

Любые наблюдения о том, как можно улучшить вышеуказанную логику, были бы великолепны.

Спасибо всем.

Ответ 4

Вы пытались использовать токен csrf в качестве параметра записи? Если не то, что вы можете сделать, это установить csrf token и token в параметрах публикации вашего запроса axios. Это решит вашу проблему.

Ответ 5

Я установил https://github.com/barryvdh/laravel-cors

для выпуска CORS Это работает для меня

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

const options = { метод: 'POST', заголовки: {'X-CSRF-TOKEN': 'xxx'}, данные: данные, URL, }; Вардар (варианты);