基于angular2实现用户登录并信息持久化的一些理解(三)

(接上篇)

上面已经提到,在用angular2调用后台接口的时候,遇到了两个问题1、请求头没有cookies;2、对两次请求,node后端都开了一个新的线程。对于这两个问题,其实我认为解决了请求头cookie的问题,后面的问题自然解决。对于cookie有什么作用,为什么要有这个cookie,看下图前后端请求模式。

《基于angular2实现用户登录并信息持久化的一些理解(三)》

《基于angular2实现用户登录并信息持久化的一些理解(三)》

《基于angular2实现用户登录并信息持久化的一些理解(三)》

不难看出,这个cookie是获取session会话中信息的凭证,只有向后台传送匹配的cookie,才能得到相应的信息,否则将创建新的session。

到这里,来看下XMLHttpRequest.withCredentials这个属性,度娘解释如下

XMLHttpRequest.withCredentials  属性是一个Boolean类型,它指示了是否该使用类似cookies,authorization headers(头部授权)或者TLS客户端证书这一类资格证书来创建一个跨站点访问控制(cross-site Access-Control)请求。在同一个站点下使用withCredentials属性是无效的。

此外,这个指示也会被用做响应中cookies 被忽视的标示。默认值是false。

如果在发送来自其他域的XMLHttpRequest请求之前,未设置withCredentials 为true,那么就不能为它自己的域设置cookie值。而通过设置withCredentials 为true获得的第三方cookies,将会依旧享受同源策略,因此不能被通过document.cookie或者从头部相应请求的脚本等访问。

angular2中http显然也是基于xml的请求,必定有这个属性。再看下http接口的请求接口说明。默认情况下,一般浏览器的CORS跨域请求都是不会发送cookie等认证信息到服务端的,除非指定了xhr.withCredentials = true,但是只有客户端单方面的设置了这个值还不行,服务端也需要同意才可以,所以服务端也需要设置好返回头Access-Control-Allow-Credentials: true;还有一点要注意的,返回头Access-Control-Allow-Origin的值不能为星号,必须是指定的域,否则cookie等认证信息也是发送不了。

Interface Details

url : string
method : string|RequestMethod
search : string|URLSearchParams|{[key: string]: any | any[]}
params : string|URLSearchParams|{[key: string]: any | any[]}
headers : Headers
body : any
withCredentials : boolean
responseType : ResponseContentType

问题找到了,就是这货!再修改下请求代码

《基于angular2实现用户登录并信息持久化的一些理解(三)》

再来看下请求头信息

《基于angular2实现用户登录并信息持久化的一些理解(三)》

《基于angular2实现用户登录并信息持久化的一些理解(三)》

显然,请求头都已经被加上了cookie,而且这个cookie都是匹配的,看似没什么问题,但是再看看请求接口的response,没有任何信息,但后台明显有返回信息,而且这个response并非每次都不返回任何信息,存在偶然性。
《基于angular2实现用户登录并信息持久化的一些理解(三)》

《基于angular2实现用户登录并信息持久化的一些理解(三)》

到这里,明显就出现了另一个问题,就是跨域,看看浏览器的console信息就知道了

XMLHttpRequest cannot load http://neil.com:8090/api/send. The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://localhost:4200' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

到这里,问题清晰了,只要解决跨域问题,整个流程就跑通。网上也有很多办法处理跨域,但如果不想用jsonp呢,那只能从服务器上动刀子。查了些资料,最靠普的无非在服务端加上request头部设置

//设置跨域访问
app.all('*', function (req, res, next) {
    res.header("Access-Control-Allow-Origin", "http://neil.com:4200");   //设置跨域访问
    res.header('Access-Control-Allow-Credentials', 'true');
    res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    res.header('Access-Control-Allow-Headers', 'Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With');
    res.header("Content-Type", "application/x-www-form-urlencoded");
    next();
});

这里说明下,‘Access-Control-Allow-Origin’必须设置请求侧的域名,不然无法跨域,不能解决问题。

《基于angular2实现用户登录并信息持久化的一些理解(三)》

现在,问题已经全部处理。

    原文作者:neil008
    原文地址: https://segmentfault.com/a/1190000009938397
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞