前端与服务器分离开发出现跨域问题,jsonp与gulp-connect注意点,angularjs改造

预备

在网络中,受到浏览器内部机制的限制,本域内,也就是自身服务器下的服务的js是不能操作其他域下的页面对象,或者去请求域下的数据,这个时候就会产生跨域问题。
有些人会奇怪,为什么cdn或者图片加载的时候,不是本域的东西,却可以请求的来,这个请大家要仔细理解一下,跨域是指js不能操作和请求其他域的,浏览器本身请求和
标签src内部的请求是不受限制的。

下面我们来说如何解决问题。

解决方案:
网上有许多的解决方案,本文的解决方案大体思路是一样,只是针对在实际解决过程遇到的一些常见问题,提出注意点,供大家参考


1.jsonp


最初用来解决跨域问题的方式,叫做JSONP,它的基本原理是:跨域的“资源嵌入”是被浏览器允许的。所以,可以通过一个script标签来嵌入一段来自其他服务器的脚本。由于这个脚本完全运行在当前域,无法访问第三方服务器的cookie等敏感信息,所以是安全的。


JSONP的缺点是它只能支持GET操作,没法支持POST等操作,但是由于兼容性好等优点,仍然有很多网站采用JSONP的方式公开自己的API供第三方调用。


在Angular中,$http内置了对JSONP的支持,它的调用接口也和其他方法没什么区别,使用起来非常简单。但是也仅仅支持get请求

2.gulp-connect与gulp-connect-proxy

当前端开发集成使用gulp的时候,可以使用这个方式进行跨域,他的原理类似于反向代理,但却有不同,内部实际做的操作,实际只是反向代理转发了请求,这样就造成了一个问题,就是也仅仅是支持get请求,无法支持post操作


3.CORS


这是W3C提供的另一种跨域方式。作为一项标准的跨域规范,CORS本应该是最值得采用的。 问题在于,老式浏览器支持CORS,而我们显然还没到可以无视老式浏览器的时候。 


CORS的原理是基于服务方授权的模式,也就是说提供服务的程序要主动通过CORS回应头来声明自己信任哪些源(协议+域名+端口)。 由于得到了服务方的授权,浏览器就可以放行来自这些域的请求了。

并且有个弊端问题是,该方式必须要服务器端开发和前端开发配合,也就是服务端的所有接口需要设置请求头,来放行,这样造成的问题是,如果项目在开发阶段或者线上项目与开发项目不是同一个版本,还好,不然,一旦服务端采用该设置,并且在设置上有问题,有很大的安全隐患,但是如果能够控制好设置,通过token控制好,也是可以得。


4.反向代理

要想解决跨域问题,最简单彻底的方法当然是把他们拉到一个域下,而这就是该“反向代理”发挥作用的时候了。


所谓反向代理,就是在自己的域名下架设一个Web服务器,这个服务器会把请求转发给第三方服务器,然后把结果返回给客户端。


这时候,在客户端看来,自己就是在和这台反向代理服务器打交道,而不知道第三方服务器的存在。


所以,如果有一个Web服务程序,它同时提供了反向代理功能和静态文件服务功能,静态文件服务负责渲染前端页面,反向代理则提供对第三方服务器的透明访问。那么前端和后端就变成了同源的,不再受同源策略的约束。


那么,有这样的Web服务程序吗?有,而且不止一个。事实上,几乎所有的主流Web服务器都提供了反向代理功能。这里仅以nginx为例来示范反向代理的配置方式,其他Web服务器请搜相应的文档自行研究。
server {
    listen 80;
    server_name your.domain.name;
    location / {
        proxy_pass http://localhost:5000/; # 把根路径下的请求转发给前端工具链(如gulp)打开的开发服务器,如果是产品环境,则使用root等指令配置为静态文件服务器
    }
    location /api/ {
        proxy_pass http://localhost:8080/service/; # 吧 /api 路径下的请求转发给真正的后端服务器
        proxy_set_header Host $http_host;  # 把host头传过去,后端服务程序将收到your.domain.name,否则收到的是localhost:8080
        proxy_cookie_path /api /service;   # 把cookie中的path部分从/api替换成/service
        proxy_cookie_domain localhost:8080 your.domain.name; # 把cookie的path部分从localhost:8080替换成your.domain.name
    }
}
这个解决方案,有时候还是会遇到一些问题,比如你们app的前端使用的是Angular开发,而pc端是使用的jquery开发,且在开发过程中强制规定contentType,这个时候,jquery的post默认的contentType与Angular默认的是不一样的,所以为了统一,还需要做一些修改,这里服务端,以java,框架为springmvc为例,
app.config(function($httpProvider) {
	$httpProvider.defaults.headers.put['Content-Type'] = 'application/x-www-form-urlencoded';
	$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

	// Override $http service's default transformRequest
	$httpProvider.defaults.transformRequest = [function(data) {
		/**
		 * The workhorse; converts an object to x-www-form-urlencoded serialization.
		 * @param {Object} obj
		 * @return {String}
		 */
		var param = function(obj) {
			var query = '';
			var name, value, fullSubName, subName, subValue, innerObj, i;

			for (name in obj) {
				value = obj[name];

				if (value instanceof Array) {
					for (i = 0; i < value.length; ++i) {
						subValue = value[i];
						fullSubName = name + '[' + i + ']';
						innerObj = {};
						innerObj[fullSubName] = subValue;
						query += param(innerObj) + '&';
					}
				} else if (value instanceof Object) {
					for (subName in value) {
						subValue = value[subName];
						fullSubName = name + '[' + subName + ']';
						innerObj = {};
						innerObj[fullSubName] = subValue;
						query += param(innerObj) + '&';
					}
				} else if (value !== undefined && value !== null) {
					query += encodeURIComponent(name) + '='
							+ encodeURIComponent(value) + '&';
				}
			}

			return query.length ? query.substr(0, query.length - 1) : query;
		};

		return angular.isObject(data) && String(data) !== '[object File]'
				? param(data)
				: data;
	}];
});


在angular的配置中加上这些,这样他的post请求就和jquery默认的一样了,都默认为 Content-Type: x-www-form-urlencodedand


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值