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

前端之家收集整理的这篇文章主要介绍了前端与服务器分离开发出现跨域问题,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

猜你在找的Json相关文章