Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React+Laravel 5.8.33 +Axios: errors when registering user with an axios.post request; clarififying the code problem

Update

Checking my network tab in my dev-tools of firefox gives me this:

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

Why is the method GET? Trying to change it from the tools, it gives that POST method isn't allowed. Also, when submitting the request, it gives the following info:

Update

I started making changes to bootstrap.js file, where my axios is required, but I had no success. I tried changing

window.axios = require('axios');

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

to

window.axios = require('axios');

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

but really, I can't get to a point. I cannot understand how the linked tutorial in my comments worked and I am starting to have a shortage of ideas on what to look. So, any help is appreciated; if someone can point to a valid reference that says, look, this is an unsolved problem, then I will implement py project with a different code; but if not, I this problem shouldn't remain unsolved. If it's a minor mistake from my part, then where exactly is it? Thanks to all.

Note: On my original posts, I didn't showed what my web routes look like. Since I am using React from inside Laravel(I used in terminal php artisan preset react ;) my web routes went from the pre-configured laravel code

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

to the new code that calls the React app:

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

Update3: I have tried(from yesterday) to change my apache2 conf and my problem remains. I don't know if this is to be taken as change though:

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: I tried changing my axios post request:

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('/')

... But, then I get

invalid header name


Original As I have mentioned before in another post, I am currently self study React and Laravel. I am trying to build a basic registration app with React as front-end and Laravel as back-end. This post is about errors coming when I fill out the registration form and try to submit it; the user doesn't gets registered and I get several errors depending on what I am trying.

If I try:

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

I get in console :

> 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 

If I try

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

then I get(I believe this an error regarding bad route definition ):

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

If I use

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

I get:

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

I am not sure anymore(I cannot clarify) if I have a CORS problem (although I have taken actions that should prevent such issues) or some other, routing or data-passing or just syntactic issue. I would go for the CORS problem(altough I have no idea what that popper.js.map notification is all about). I am posting the code below.


Update1:

I just ran my code in Chrome browser with the

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

and I got the

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 doesn't 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

It seems I have a CORS problem... and I cant understand from yesterday and all day today how to handle it.


Some code:

My App(parent) component contains a function that gets passed to a Register(child) component; this function handles the registration process

        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 component just contains the form and returns the input data. Using a console.log command, I am verifying that the data are indeed available in my App and inside my register function. If asked, I can post the code.

At my back-end I have:

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 doesn't 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', 'UserController@login');
            Route::post('/user/register', 'UserController@register');
        });

API.php(middleware)

<?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);
        }
    }

So again, I cannot clarify what the issue is exactly and the registration procedure doesn't work.

like image 980
Constantine Black Avatar asked Aug 28 '19 14:08

Constantine Black


1 Answers

Preflight requests are an HTTP-OPTIONS request made by a client to the server to verify that it supports CORS protocol.

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

The way to go is to register a route in your server that returns a response with necessary access control policy headers. For example:

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', '.*');

This is similar to the middleware approach in your question except that the middleware is attached to routes but provides no fallback for options request to those routes.

like image 93
Oluwafemi Sule Avatar answered Nov 19 '22 03:11

Oluwafemi Sule