提交表单后,网址应该更改吗?

时间:2019-11-02 00:06:16

标签: angular express

我正在从localhost:4200服务Angular,从localhost:3000服务Express。在我的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更改为表单action属性(https://localhost:3000/users/sign-up)中列出的URL吗?还是将数据提交到action属性URL(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并向{{ 1}}(假设每个请求只允许一个响应)?

谢谢!

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

UPDATE UPDATE UPDATE UPDATE

我进行了@John Mgbako建议的出色更改,但是现在有了一个新问题,即myu服务器尝试针对每个localhost:4200/sign-up请求两次保存相同的文档(请在下面查看更多详细信息)。我现在有:

模板

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'})
  }

}

**问题现已存在:

  
    
        
  1. 要尝试按照每次发布请求将相同文档保存2倍的服务器项。 (它正确地保存在MongoDB中,然后过一会儿,当服务器尝试再次保存同一文档时,我收到服务器端Dup Key错误。)
  2.     
  3. 没有 . . . . . . user.save().then(()=> { res.cookie("SESSIONID", user.generateJWT(), {httpOnly:true, secure:true}); . . . . . . 元素,点击返回输入元素时没有发生
  4.     
  5. 如果使用BUTTON元素,则该表单几乎是两次提交的表单。击中BUTTON /从最后一个ENTER中冒出来是一种要求,而在单击INPUT按钮时又是一种要求? (顺便说一句,表格如何知道按钮是“提交”按钮?)。
  6.     
  7. 我期望的行为是,仅当选中SUBMIT按钮时,才提交表单,而不是在用户输入SUBMIT时输入表单。 **
  8.     
  

有什么主意如何解决这种奇怪的行为,即服务器在每个RETURN请求中尝试两次保存文档?

最终更新 添加POST res.cookie()`解决了该问题(即后端不再尝试两次保存文档)!

2 个答案:

答案 0 :(得分:2)

这个问题有几个方面。

  1. 当可以使用Angular的form时,为什么要使用action的{​​{1}}属性来提交form?这样,当您从Express API获得成功响应后,就可以更好地控制将用户重定向到何处。

  2. 理想情况下,应该将用户导航到某种着陆页。这既可以是仪表板页面,也可以是用户在注册/登录后应该登陆的主应用程序登陆页面,或者也可以是向您显示一条消息的页面,表明用户已将电子邮件发送到其注册电子邮件。带有确认链接或类似名称的地址。

  3. 考虑到您提到了HttpClient路由,可以肯定地假设您还实现了路由。因此,您可以很好地将Router作为依赖项注入并在其上调用navigate,以便在成功响应后导航用户。

  4. 最后,由于Angular应用程序和Express应用程序在单独的PORT上运行,您可能会收到CORS错误。因此浏览器将阻止CORS。您可以使用cors中间件来处理它。

答案 1 :(得分:2)

首先,您不以角的形式使用action属性,您可以反应性地使用表单或模板,例如

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

应为:

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

在组件中添加一个onSubmit()函数,它将使用角度HttpClient处理验证和所有请求调用

第二个内容安全策略:与以下事实有关:您的后端代码没有设置CORSCORS来允许某些URL。您可以访问此链接Express CORS,了解如何在后端代码中实施。您还可以使用代理配置来处理您的Angular项目上的CORS,请访问此链接Proxy Config,了解如何实现。