Браузер отменяет http запросы из углового приложения - PullRequest
0 голосов
/ 21 января 2019

До недавнего времени у меня не было проблем с взаимодействием моего внешнего и внутреннего приложений. По какой-то причине теперь, когда мое угловое приложение отправляет запросы http в мое приложение rails api (Chrome или Firefox), я получаю эту ошибку:

enter image description here

enter image description here

Я пытался изменить настройки Cors в моем приложении rails, но это не сработало. Я недавно обновил до angular 7, так что я не знаю, что это и является причиной этого.

У меня есть приложение ruby-on-rails 5 api и приложение angular 7.

Это мой cors.rb:

# application.rb
    config.middleware.insert_before 0, Rack::Cors do
      allow do
        origins '*'

        resource '*',
          headers: :any,
          #expose:  ['access-token', 'expiry', 'token-type', 'uid', 'client'],
          methods: [:get, :post, :put, :patch, :delete, :options, :head]
      end
    end

Конфигурации заголовков в сервисах angular:

const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};

Я хотел бы знать, как это исправить, и узнать, это проблема с бэкэндом или с внешним интерфейсом. Заранее спасибо.

EDIT потому что это может быть проблема с моим угловым приложением, вот соответствующий код:

// app-routing.module

// Routing array - set routes to each html page
const appRoutes: Routes = [
  { path: 'login/:id', canActivate: [AuthGuard], children: [] },
  { path: '', canActivateChild: [AuthGuard], children: [
    { path: '', redirectTo: '/courses', pathMatch: 'full' },
    { path: 'courses', component: CourseListComponent,  pathMatch: 'full'},
    { path: 'courses/:courseId', component: CourseDetailComponent, pathMatch: 'full' },
    { path: 'courses/:courseId/unit/:unitId', component: CoursePlayComponent,
      children: [
        { path: '', component: CourseListComponent },
        { path: 'lesson/:lessonId', component: CourseLessonComponent, data:{ type: 'lesson'} },
        { path: 'quiz/:quizId', component: CourseQuizComponent, data: {type: 'quiz'} }
      ]}
    ]},
  { path: 'welcome', component: LandingPageComponent, pathMatch: 'full' },
  { path: '**', component: PageNotFoundComponent, pathMatch: 'full' }];

// auth.guard.ts

canActivate(route: ActivatedRouteSnapshot, state:
       RouterStateSnapshot): boolean |
       Observable<boolean> | Promise<boolean> {
         // save the id from route snapshot
         const id = +route.params.id;
         const course_id = +route.params.courseId;

         // if you try to logging with id
         if (id) {
           this.router.navigate(["/courses"]);
           return this.authUserService.login(id);
         }
         // if you're already logged in and navigate between pages
         else if (this.authUserService.isLoggedIn()){
           if (course_id){
             // check if someone try to access a locked course
             if (this.authUserService.isCourseNotPartOfTheSubscription(course_id)){
               this.router.navigate(["/welcome"]);
               return false;
             }
             else
               return true;
           }
           else
             return true;
         }
         else {
           this.router.navigate(["/welcome"]);
           return false;
         }
        }

      canActivateChild(route: ActivatedRouteSnapshot,state: RouterStateSnapshot): boolean |
      Observable<boolean> | Promise<boolean> {
         return this.canActivate(route, state);
       }

// auth-user.service.ts

@Injectable()
export class AuthUserService implements OnDestroy {
  private user: IUser;
  private errorMessage: string;

  constructor(private userService: UserService,
              private userProgressService: UserProgressService) {
                userProgressService.connectUser();
                userProgressService.setFlagLanName();
              }

  login(id: number) {
    return this.userService.getUser(id).pipe(
      map((user) => {
        this.user = user;
        localStorage.setItem('user', JSON.stringify(this.user));
        localStorage.setItem('token', 'JWT');
        
        // this service used for user-progress requests so connectUser
        // just get items from localStorage
        this.userProgressService.connectUser();
        return true;
      }),
      catchError((error) => {
        this.errorMessage = <any>error;
        return of(false);
      })
    );
  }

  // @returns {Observable<T>}
  isLoggedIn() {
   return !!localStorage.getItem('token');
  }

  // check if a user try to access a locked course
  isCourseNotPartOfTheSubscription(course_id){
    return this.userProgressService.isLocked(course_id);
  }
}

// user.service.ts

const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};

@Injectable()
export class UserService {
  private url = 'http://localhost:3000/users';
  private diploma_url = 'http://localhost:3000/diplomas';

  constructor(private http: HttpClient) {  }

  // Get Single user by id. will 404 if id not found
  getUser(id: number): Observable<IUser> {
    const detailUrl = `${this.url}/${id}` + '.json';

    return this.http.get<IUser>(detailUrl)
        .pipe(catchError(this.handleError));
  }

  // call mark_lesson_as_completed in backend
  updateCompletedLessons(user_id: number, course_id: number, param: any): Observable<any> {
    const userUrl = `${this.url}/${user_id}` + '.json';
    let body = JSON.stringify({
      course_id: course_id,
      completed_lesson: param
    });

    return this.http.patch(userUrl, body, httpOptions)
      .pipe(
        tap(_ => console.log(`updated user ${user_id} with this entry: ${param}`)),
        catchError(this.handleError)
      );
  }

  // call mark_quiz_as_completed in backend
  updateCompletedQuizzes(user_id: number, course_id: number, param: any): Observable <any> {
    const userUrl = `${this.url}/${user_id}` + '.json';
    let body = JSON.stringify({
      course_id: course_id,
      completed_quiz: param
    });

    return this.http.patch(userUrl, body, httpOptions)
      .pipe(
        tap(_ => console.log(`updated user ${user_id} with this entry: ${param}`)),
        catchError(this.handleError)
      );
  }

  // call mark_course_as_completed in backend
  updateCourseStatus(user_id: number, course_id: number, param: any): Observable <any> {
    const userUrl = `${this.url}/${user_id}` + '.json';
    let body = JSON.stringify({
      course_id: course_id,
      completed: param
    });

    return this.http.patch(userUrl, body, httpOptions)
      .pipe(
        tap(_ => console.log(`updated user ${user_id} with this entry: ${param}`)),
        catchError(this.handleError)
      );
  }

  // call serve_diploma in users
  getDiploma(user_id: number) {
    const diplomaUrl = `${this.diploma_url}/${user_id}`;
    return diplomaUrl;
  }


  // // Handle Any Kind of Errors
  private handleError(error: HttpErrorResponse) {
    // A client-side or network error occured. Handle it accordingly.
    if (error.error instanceof ErrorEvent) {
      console.error('An error occured:', error.error.message);
    }

    // The backend returned an unsuccessful response code.
    // The response body may contain clues as to what went wrong.
    else {
      console.error(
        'Backend returned code ${error.status}, ' +
        'body was ${error.error}');
    }

    // return an Observable with a user-facing error error message
    return throwError(
      'Something bad happend; please try again later.');
  }
}
...