Должен ли URL-адрес измениться после отправки формы? - PullRequest
0 голосов
/ 02 ноября 2019

Я служу Angular от localhost:4200 и Express от localhost:3000. В моем маршруте localhost:4200/sign-up у меня есть форма с <form action=https://localhost:3000/users/sign-up>.

<form #form [formGroup]="userForm" method="POST" action="https://localhost:3000/users/sign-up">

 . . . 
 . . . 

  <input type="submit" value="Submit" (click)="form.submit()" [disabled]="!userForm.valid || !usernameIsUnique">
</form>

. После отправки формы я обрабатываю отправку в Express, сохраняю данные (используя user.save()) и простопроверьте, как все работает, завершите маршрут, отправив ответ с res.json(JSON.parse('{"foo": "bar"}').

exports.user_create_post = [
   . . . 
    (req,res,next) => {
        var user = new UserObj(
            { . . . });
        user.save(function(err) { . . . });
        res.json(JSON.parse('{"foo": "bar"}'));
 }]

После res.json() мой URL остается на https://localhost:3000/users/sign-up, и у меня появляется консольная ошибка: Content Security Policy: The page’s settings blocked the loading of a resource at https://localhost:3000/favicon.ico (“default-src”). (Для простоты здесь я постараюсь рассмотреть проблему Content Security Policy в отдельном посте).

Предполагая, что ошибок не было, должен ли URL оставаться на https://localhost:3000/users/sign-up после ответа res.json(), или URL браузера должен вернуться к referrer, то есть localhost:4200/sign-up? Другими словами, в обычном случае без ошибок, действительно ли при отправке формы URL-адрес браузера изменяется на URL-адрес, указанный в свойстве action (https://localhost:3000/users/sign-up)? Или он отправляет данные на URL-адрес свойства action (https://localhost:3000/users/sign-up), но сохраняет URL-адрес браузера на referrer URL (localhost:4200/sign-up)?

Если действительно отправка формы изменяет URL-адресна https://localhost:3000/users/sign-up, означает ли это, что res.json() также отправляется на https://localhost:3000/users/sign-up (вместо localhost:4200/sign-up)? Если это так, это объясняет, почему у меня проблемы. Кроме того, предполагая, что res.json() отправлено на https://localhost:3000/users/sign-up, а не на реферер (localhost:4200/sign-up), как я могу перенаправить на localhost:4200/sign-up И отправить ответ JSON на localhost:4200/sign-up (учитывая, что только один ответразрешено за запрос)?

Спасибо!

===========================

ОБНОВЛЕНИЕ ОБНОВЛЕНИЕОБНОВЛЕНИЕ ОБНОВЛЕНИЕ

Я внес отличные изменения, предложенные @John Mgbako, но теперь возникла новая проблема, заключающаяся в том, что myu server пытается сохранить один и тот же документ два раза за запрос POST (см. Подробностиниже). Теперь у меня есть:

ШАБЛОН

<form #f="ngForm" [formGroup]="userForm" (ngSubmit)="doSignUp(f)">
    <ng-container *ngFor="let key of keyArr; index as i"> 

    <label [hidden]='key[1]'> {{key[2]}}
      <div>
          <input *ngIf="key[1]==='password' type='password' [formControlName]='key[0]' id={{key[0]}} name={{key[0]}}/>
          <input *ngIf="key[1]!=='password' type='text' [formControlName]='key[0]' id={{key[0]}} name={{key[0]}}/>
      </div>
     </label>
    <br/>

    </ng-container>
    <button>Submit</button>

</form>

КОМПОНЕНТ

@Injectable()
export class SignupComponent implements OnInit, OnChanges {
  data: Object;
  keys: string[];
  keyArr: any[] = [];
  formCtls: any = {};
  userForm: FormGroup;
  cookieValue: string;

  constructor(private member: MemberService, 
    private fb: FormBuilder, 
    private cs: CookieService, 
    private router: Router,
    private route: ActivatedRoute) { }

  ngOnChanges() {
    // IF COOKIE EXISTS THEN ALREADY SIGNED UP, SO REDIRECT . . .
    console.log("IN ON_CHANGES");
    const cookie = this.cs.get("SESSIONID"); 
    if (cookie) {
      console.log(`ID: ${JSON.stringify(cookie)}`);
      debugger;
      this.router.navigateByUrl('../two-fa',{relativeTo: this.route})
    } 
  }

  ngOnInit() {

    this.member.getSignupForm().subscribe((data)=>{
      this.data = data;
      this.keys = Object.keys(data["authData"]);
      this.keys.forEach((key,idx) => {
        let datArr = [];
          this.formCtls[key] = new FormControl('', {updateOn: 'blur'});
          if (key !== '_id') {
            datArr.push(key,
              data["authData"][key]["attr"]["hidden"],
              data["authData"][key]["attr"]["label"]);
          } else {
            datArr.push(key,true,'');
          }
        if (key === 'password' || key === 'hash') {
          let datArr = [];
          this.formCtls['password2'] = new FormControl('');
          datArr.push('password2', false, 'Password (again): ');
          this.keyArr.push(datArr);          
        }
      });
      this.userForm = new FormGroup(this.formCtls);
      if (this.data) this.got_data = true; 
      console.log("OnInit Data: " + this.data_string);
      this.cs.set('member-cookie','{login-name: ' + data["authData"]["username"]["value"].pop() + '}');
      this.cookieValue = this.cs.get('member-cookie');
      console.log ("Cookie: " + this.cookieValue);

      //Set up observable on the Username Input, to check if Unique
      this.formCtls['username'].valueChanges.pipe(
        filter((text: String) =>text.length > 2),
        tap(text=>console.log("Text 1: " + text)),
        debounceTime(10),
        distinctUntilChanged(),
        switchMap((text: String) =>this.member.getUnique(text.toLowerCase()))
      ).subscribe(r=> {console.log(`Result from unique get(): ${r}`); 
            this.usernameIsUnique = (r > 0) ? false : true; // r is # of instances in DB
            console.log(`Unique? (length: ${r}): ${this.usernameIsUnique}`); });
    });
  }

  doSignUp(f: NgForm) {
    this.member.postSignupForm(f).subscribe((res)=>console.log(`RES: ${JSON.stringify(res)}`));
  }

}

АВТОСЕРВИС (ОБСЛУЖИВАНИЕ ЧЛЕНА)

@Injectable({
  providedIn: 'root'
})
export class MemberService {
  host_url: string = "https://localhost:3000/users/";
  signup_url: string = this.host_url+"sign-up";
  data: string = '';

  constructor(private http: HttpClient) { }

  getSignupForm(): Observable<any> {

    return this.http.get(this.signup_url,{responseType: 'json'})

  }

  postSignupForm(f: NgForm): Observable<any> {
    return this.http.post(this.signup_url, f.value);
  }

  getUserIdFromRoute(route: ActivatedRoute): Observable<string> {
    return route.paramMap.pipe(
      map((params: ParamMap) => params.get('id'))
    )
  }

  getUnique(s: String): Observable<any> {
    return this.http
      .get(`${this.host_url}unique?username=${s}`, {responseType: 'json'})
  }

}

МАРШРУТ СЕРВЕРА

   . . . 
   . . . 
            user.save().then(()=> {
                res.cookie("SESSIONID", user.generateJWT(), {httpOnly:true, secure:true});

   . . . 
   . . . 

** ПРОБЛЕМА (С) ЕСТЬ / СЕЙЧАС:

  1. СЕРВЕР СДЕЛАЕТ, ЧТОБЫ ПОПРОБОВАТЬ, ЧТОБЫ СОХРАНИТЬ ЖЕ ДОКУМЕНТ 2 раза на ЗАПРОС ПОЧТЫ. (Он сохраняется правильно в MongoDB, затем через некоторое время я получаю сообщение об ошибке Dup Key на стороне сервера, когда сервер снова пытается сохранить тот же документ).
  2. Без элемента BUTTON ЭЛЕМЕНТ, НИЧЕГО НЕ ПРОИСХОДИТ, КОГДА НАХОДЯТСЯВЕРНУТЬСЯ В ВХОДНЫЕ ЭЛЕМЕНТЫ
  3. С BUTTON ЭЛЕМЕНТОМ, ПОЧТИ ПОЧЕМУ, ЕСЛИ ФОРМА ПРЕДСТАВЛЯЕТСЯ ДВАЖДЫ. ВОЗМОЖНО, ЭТО ОДИН ЗАПРОС, КОГДА ДУМАЕТ ENTER / ВЗРЫВ ИЗ ПРОШЛОГО INPUT И ОДИН ЗАПРОС, КОГДА НАЖИМАЕТ НА КНОПКУ SUBMIT? (КСТАТИ, КАК ФОРМА ЗНАЕТ КНОПКУ «КНОПКА»?).
  4. МОЕ ЖЕЛАННОЕ ПОВЕДЕНИЕ, ЧТО ФОРМА ПРЕДСТАВЛЯЕТ ТОЛЬКО, КОГДА КНОПКА SUBMIT НАЖИМАЕТСЯ, НЕ КОГДА ПОЛЬЗОВАТЬСЯ RETURN ВХОДЫ. **

Есть идеи, как исправить это странное поведение, при котором сервер пытается сохранить документ дважды за POST запрос?

ЗАКЛЮЧИТЕЛЬНОЕ ОБНОВЛЕНИЕ Добавление res.send('done') after res.cookie () `решило проблему (т. Е. Серверная часть больше не пытается сохранить документ дважды)!

Ответы [ 2 ]

2 голосов
/ 02 ноября 2019

Во-первых, вы не используете атрибут действия в форме в угловом формате, вы можете использовать форму реактивно или шаблон, например:

<form #form [formGroup]="userForm" method="POST" action="https://localhost:3000/users/sign-up">

должно быть:

<form [formGroup]="userForm" (ngSubmit)="onSubmit()">

добавитьФункция onSubmit () в компоненте, которая будет обрабатывать валидацию и весь ваш запрос, используя угловую HttpClient

Secondly Content Security Policy: связана с тем фактом, что ваш бэкэнд-код не имеет CORS или CORS был установлен для разрешения определенного URL. Вы можете перейти по этой ссылке Express CORS о том, как реализовать в своем бэкэнд-коде. Вы также можете использовать конфигурацию Proxy для обработки CORS в своем угловом проекте, перейдите по этой ссылке Конфигурация прокси , чтобы узнать, как ее реализовать.

0 голосов
/ 02 ноября 2019

У этого вопроса есть несколько аспектов.

  1. Зачем использовать атрибут form action для отправки form, когда вы можете использовать Angular's HttpClient? Таким образом, вы получите больше контроля над тем, куда перенаправить пользователя после того, как вы получите успешный ответ от Express API.

  2. В идеале пользователь должен перейти на какую-то целевую страницу,Это может быть либо страница панели мониторинга, либо целевая страница основного приложения, куда пользователь должен приземлиться после регистрации / входа в систему, либо это также страница, на которой вы показываете им сообщение о том, что электронное письмо было отправлено на его зарегистрированную электронную почту. адрес с ссылкой для подтверждения или чем-то в этом роде.

  3. Учитывая, что вы упомянули маршрут /sign-up, было бы безопасно предположить, что вы также внедрили маршрутизацию. Таким образом, вы можете очень хорошо, вставить Router в качестве зависимости и вызвать navigate на нем для навигациипользователь после успешного ответа.

  4. Наконец, вы, вероятно, получите ошибку CORS, так как ваше приложение Angular и ваше приложение Express работают на разных портах. Таким образом, браузер будет блокировать CORS на нем. Вы можете использовать промежуточное программное обеспечение cors, чтобы справиться с ним.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...