Angular4.x项目如何实现跨域
跨域
跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对 javascript 施加的安全限制。
浏览器的同源策略会导致跨域,这里同源策略又分为以下两种:
- DOM 同源策略:禁止对不同源页面 DOM 进行操作。这里主要场景是 iframe 跨域的情况,不同域名的 iframe 是限制互相访问的。
- XmlHttpRequest 同源策略:禁止使用 XHR 对象向不同源的服务器地址发起 HTTP 请求。
什么情况下跨域了?
只要协议、域名、端口有任何一个不同,都被当作是不同的域,之间的请求就是跨域操作。举个例子:http://www.example.com(:80)/
,调用http://www.example.com:8080/
(端口号不同)http://www.example.com(:80)/
,调用http://api.example.com/
(子域名不同)http://www.example.com(:80)/
,调用https://www.example.com/
(协议不同)
上面三种都存在跨域问题,想必有些人肯定会困惑,浏览器为什么会有跨域的限制呢?有经验的人肯定知道,跨域限制主要是为了安全考虑。
解决方式
JSONP
基本原理就是通过动态创建 script 标签,因为 script 没有跨域限制。使用方法就不赘述了,但是要注意 JSONP 只支持 GET 请求,不支持 POST 请求。
CORS
实现 CORS 通信的关键是服务器,因为不是太懂服务端,这里只说关键设置,需要在 response header 中设置如下两个字段:
1 | header('Access-Control-Allow-Origin: *'); //允许所有来源访问,或者换成指定地址 |
我在 nginx 上这样设置的:
1 | location / { |
具体教程参见:跨域资源共享CORS详解
Cors在nginx上的设置:CORS on Nginx
代理
这里分为两种环境:开发环境和生产部署环境。
本地测试一般都属于开发环境,如果用了Angular-cli搭建项目,跨域就简单了,只需两步:
在项目根目录新建一个文件
proxy.conf.json
,添加如下内容1
2
3
4
5
6
7{
"/v2": {
"target": "https://api.douban.com",
"secure": false,
"changeOrigin": true //记得加这句
}
}修改同目录下的
package.json
的 scripts 内容1
2
3
4
5{
"scripts": {
"start": "ng serve --proxy-config proxy.conf.json --open"
}
}
然后向这个 url 发起 get 请求/v2/movie/top250?count=10
,这样就能轻松实现跨域了。
但是项目要部署了怎么办?上面这个方法还管用吗?答案是当然不能,因为有些设置没有生效到服务器。
浏览器有跨域限制,但是服务器不存在跨域问题,所以可以由服务器请求所要域的资源再返回给客户端。
这里不得不说说 nginx 的反向代理,利用 nginx 反向代理实现跨域,是最简单的跨域方式,支持所有浏览器,并且不会影响服务器性能。这是一种对于任何项目都通用的方法!nginx下载链接
下面是我写的一个简单的 location 匹配规则。
1 | location ^~ /v2/movie/ { |
假设前端请求 URL 为:/v2/movie/top250?count=10
,location会匹配以/v2/movie/
为开头的地址,rewrite 重写 url,$1
引用的是括号里的内容(.*)
,last 一般写在 server 和 if 中,而 break 一般使用在 location 中。proxy_pass 转发请求到真实服务器,其实真实的请求url为:https://api.douban.com/v2/movie/top250?count=10
。
常用正则
. : 匹配除换行符以外的任意字符
? : 重复0次或1次
+ : 重复1次或更多次
* : 重复0次或更多次
\d : 匹配数字
^ : 匹配字符串的开始
$ : 匹配字符串的结束
{n} : 重复n次
{n,} : 重复n次或更多次
[c] : 匹配单个字符c
[a-z] : 匹配a-z小写字母的任意一个
总结
如果你要请求的是其他公司开发提供的接口,例如上面的豆瓣api,那么 jsonp 和 nginx代理 是不错的方案;
要是自己公司开发的接口,例如:
http(s)://api.example.com/*
,那么 CORS 和 nginx代理 是最合适的方案,一般的项目采用前者,大型网站可能要做负载均衡,Apache 结合 nginx 一起用;其实项目中这三种方法可以结合使用,从而可以发挥出更多的功能。