简体   繁体   中英

Adding any options or headers on the Angular 2 http.post sends OPTIONS

I am trying to send token information back to the server over http.post() . If I remove the options from it it sends a POST but if I add them back on it sends OPTIONS which is rejected from the server code. I tried removing the "withCredentials" as well.

export class EntityService {

    public entity: EntityModel;
    private options: RequestOptions;

    constructor( @Inject(Http) private http: Http, @Inject(AuthenticationService) authService) {
        let headers = new Headers({ 'X-Authorization': 'Bearer ' + authService.token});
        this.options = new RequestOptions({ headers: headers, withCredentials: true });
    }

    public store(entity: EntityModel): Observable<string> {

        var request;
        if (!entity.uuid) {
            request = this.http.post("http://localhost:8080/api/entity", JSON.stringify(entity), this.options);
        }
        else {
            request = this.http.put("http://localhost:8080/api/entity", JSON.stringify(fact), this.options);
        }
        return request.map((res: Response) => res.text());
    }
}

My authentication service looks like this:

import { Injectable, Inject } from '@angular/core';
import { Http, Headers, Response } from '@angular/http';
import { Observable } from 'rxjs';
import 'rxjs/add/operator/map'

//http://jasonwatmore.com/post/2016/08/16/angular-2-jwt-authentication-example-tutorial
@Injectable()
export class AuthenticationService {
    public token: string;

    constructor(@Inject(Http) private http: Http) {
        // set token if saved in local storage
        var currentUser = JSON.parse(localStorage.getItem('currentUser'));
        this.token = currentUser && currentUser.token;
    }

    login(username: string, password: string): Observable<boolean> {;
        console.log("login...");
        return this.http.post('http://localhost:8080/api/auth/login', JSON.stringify({ username: username, password: password }))
            .map((response: Response) => {
                // login successful if there's a jwt token in the response
                let token = response.json() && response.json().token;
                if (token) {
                    // set token property
                    this.token = token;

                    // store username and jwt token in local storage to keep user logged in between page refreshes
                    localStorage.setItem('currentUser', JSON.stringify({ username: username, token: token }));

                    // return true to indicate successful login
                    return true;
                } else {
                    // return false to indicate failed login
                    return false;
                }
            });
    }

    logout(): void {
        // clear token remove user from local storage to log user out
        this.token = null;
        localStorage.removeItem('currentUser');
    }
}

Here is my Spring configuration:

@SpringBootApplication
public class SpringBootApp extends WebMvcConfigurerAdapter {

    private boolean workOffline = true;
    private boolean setupSchema = false;
    private IGraphService graphService;
    private DbC conf;

    @Autowired
    public SpringBootApp(IGraphService graphService, DbC conf)
    {
        this.graphService = graphService;
        this.conf = conf;
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(SpringBootApp.class, args);
    }

    @Bean
    public Filter caseInsensitiveRequestFilter() {
        return new CaseInsensitiveRequestFilter();
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("http://localhost:3000")
                .allowedMethods("GET", "PUT", "POST", "DELETE","OPTIONS");
    }

    @Bean
    public FilterRegistrationBean corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://localhost:3000");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        bean.setOrder(0);
        return bean;
    }
}

I really don't know what to do since I am following what is being said in Angular2 OPTIONS method sent when asking for http.GET and this is not a preflight request. I had this issue earlier with the wrong content-type.

The OPTIONS request is made by the browser alone. Angular is not involved at all.

"and this is not a preflight request." - it definitely is.

You need to configure your server to respond properly to the OPTIONS request or ensure that the Angular application is loaded from the same server (also same port) as where you make the request to.

The actual fix was due to two reasons: improper CORS implementation - for more please have a look here: Spring 4/5 global CORS configuration doesn't work giving `No 'Access-Control-Allow-Origin' header is present on the requested resource`

Then when I was POSTing after the login I was getting error 415 Unsupported Media Type . After following the instructions here: POST JSON fails with 415 Unsupported media type, Spring 3 mvc

I added Content-Type and Accept header on my request and it fixed the problem. It seems that Content-Type is what was actually needed.

export class EntityService {

    public entity: EntityModel;
    private options: RequestOptions;

    constructor( @Inject(Http) private http: Http, @Inject(AuthenticationService) authService) {
        let headers = new Headers({ 
           'X-Authorization': 'Bearer ' + authService.token,
           'Content-Type': 'application/json'
        });
        this.options = new RequestOptions({ headers: headers, withCredentials: true });
    }

    public store(entity: EntityModel): Observable<string> {

        var request;
        if (!entity.uuid) {
            request = this.http.post("http://localhost:8080/api/entity", JSON.stringify(entity), this.options);
        }
        else {
            request = this.http.put("http://localhost:8080/api/entity", JSON.stringify(fact), this.options);
        }
        return request.map((res: Response) => res.text());
    }
}

Using http post like this

import { Http, Headers, Response, Request } from '@angular/http';

let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('X-Authorization', this.token);
headers.append('Authorization', 'Bearer ' + jwtToken);

return this.http.post(url, data, {headers})
  .map(res => { console.log(res) })
  .catch(err => { console.log(err) } );

Note this example returns an Observable that you can subscribe to. Also my example

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM