开发者社区> tony~tian> 正文

js跨域的研究

简介: 在开发中总是会遇到,接入层可能去调用其它域名下服务的api,crud数据,可是在这中间会出现js的同源策略,导致同一个DOM不能用多个源加载数据,已确保安全性。 在数据远程调用的设计时候,要考虑性能又要考虑安全性,下边为总结的跨域三种实现: 1:使用ACAO(‘Access-Control-Allow-Origin’)设置响应头域名访问-->问题低版本的ie(10及以下)和个
+关注继续查看

在开发中总是会遇到,接入层可能去调用其它域名下服务的api,crud数据,可是在这中间会出现js的同源策略,导致同一个DOM不能用多个源加载数据,已确保安全性。

在数据远程调用的设计时候,要考虑性能又要考虑安全性,下边为总结的跨域三种实现:

1:使用ACAO(‘Access-Control-Allow-Origin’)设置响应头域名访问-->问题低版本的ie(10及以下)和个别浏览器并不支持。
2:使用jsonp实现跨域数据请求,可以但是,所有的请求会过滤成GET请求,如果安全数据的读写,有不安全因素。
3:使用form表单提交+target属性指向iframe中代码解析,可以处理,“稍微”有点麻烦。
测试添加配置本地的host:C:\Windows\System32\drivers\etc\HOSTS

10.1**.11.76 www.baidux.com
10.1**.11.76 www.alibabax.com

1:ACAO

服务器(spring-mvc):

①:配置web.xml,过滤所有的*.json或自定义其他结尾的请求:

	<filter>
		<description>js跨域</description>
		<filter-name>JsCrossDomainFilter</filter-name>
		<filter-class>cn.***.filter.JsCrossDomainFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>JsCrossDomainFilter</filter-name>
		<url-pattern>*.json</url-pattern>
	</filter-mapping>
②:cn.***.filter.JsCrossDomainFilter实现代码:

package cn.***.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.module.util.NetworkUtil;

/**
 * js跨域设置过滤器
 * @author Tony_tian
 *  过滤:1:请求浏览器类型记录,js跨域设置
 *  	2:为了不多余设置其他请求,此过滤器只过滤:*.json结尾的请求
 *  注:浏览器兼容注解:
 *  	a:大概在iex~10浏览器:
 *  	 ①:Ajax的error打印出来提示no transport:解决:js中第一行加入即可:jQuery.support.cors = true; 
 *  	 ②:error没有权限:IE浏览器的安全性设置问题:
 *  		解决:点击IE浏览器的的“工具->Internet 选项->安全->自定义级别”将“其他”选项中的“通过域访问数据源”选中为“启用”或者“提示”,点击确定就可以了。
 * */
public class JsCrossDomainFilter implements Filter{
	//日志
	private static final Logger LOG = LoggerFactory.getLogger(JsCrossDomainFilter.class);
	@Override
	public void destroy() {
		
	}
	
	@Override
	public void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;
		String type = NetworkUtil.getBrowser(request);
		NetworkUtil.setJsCrossDomain(type, response);
		LOG.info("请求浏览器类型:" + type + "---> js跨域已设置");
		chain.doFilter(request, response);
	}

	@Override
	public void init(FilterConfig config) throws ServletException {
		
	}
}
③:NetworkUtil实现代码:

package com.module.util;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.util.StringUtils;
/**
 * 获取请求地址, ip地址
 * @author Administrator
 *
 */
public class NetworkUtil {
	

	public static String getCurrentURL( HttpServletRequest request ) {
		StringBuffer url = new StringBuffer( );
		String appName = request.getContextPath( );

		if ( appName != null && appName.trim( ).length( ) > 0 && !appName.trim( ).equals( "/" ) )
			url.append( appName );
		String page = request.getServletPath( );
		if ( page != null )
			url.append( page );
		String queryString = request.getQueryString( );
		if ( queryString != null )
			url.append( "?" + queryString );

		return url.toString( );
	}

	public static String getIpAddr( HttpServletRequest request ) {
		 String ip = request.getHeader("X-Forwarded-For");
         if(!StringUtils.isEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){
             //多次反向代理后会有多个ip值,第一个ip才是真实ip
             int index = ip.indexOf(",");
             if(index != -1){
                 return ip.substring(0,index);
             }else{
                 return ip;
             }
         }
         ip = request.getHeader("X-Real-IP");
         if(!StringUtils.isEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){
             return ip;
         }
         return request.getRemoteAddr();

	}
	
	public static String getBrowser(HttpServletRequest request){
		String userAgent = request.getHeader("user-agent");
		if(userAgent.contains("MSIE")){
			return "ie";
		}else if(userAgent.contains("Firefox")){
			return "firefox";
		}else if(userAgent.contains("Chrome")){
			return "chrome";
		}else if(userAgent.contains("Safari")){
			return "safari";
		}else if(userAgent.contains("Opera")){
			return "opera";
		}
		return "other";
	}
	
	/**
	 * 服务器端设置js请求跨域。<br>
	 * 注:javascript的同源策略:同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性。
	 *    如果它们的协议、端口(如果指明了的话)和主机名都相同。则他们属于同源。
	 *    简单说:浏览器限制脚本只能和同协议、同域名、同端口的脚本进行交互。<br>
	 * 注: 由于IE8-IE10不支持通过设置Access-Control-Allow-Origin头的方式,所以对于IE需要按照IE提供的方案使用XDomainRequest对象解决。<br>
	 *	      备注:http://msdn.microsoft.com/en-us/library/ie/cc288060(v=vs.85).aspx <br>
	 *	      在使用此方法时在后端为了安全起见最好设置允许那些域进行跨域访问,如“shop.weibaobei.com",多个域名直接用“,”分开
	 * 注:addHeader()方法用指定的值添加 HTML标题。该方法常常向响应添加新的 HTTP标题。它并不替代现有的同名标题。一旦标题被添加,将不能删除。
	 * @author Tony_tian
	 * @param type 如:request.getParameter("type"); request 代表客户端http请求信息对象
	 * @param response 代表服务器端http响应信息对象
	 * */
	public static final void setJsCrossDomain(String type, HttpServletResponse response){
		if("IE".equalsIgnoreCase(type)){
			//对于IE需要按照IE提供的方案使用XDomainRequest对象解决
			response.addHeader("XDomainRequestAllowed", "1");
		}else{
			//'*'表示允许所有域名访问,可以设置为指定域名访问,多个域名中间用','隔开
			response.addHeader("Access-Control-Allow-Origin", "*");
		}
	}
}
注:可配置更详细:

response.addHeader( "Access-Control-Allow-Origin", "*" ); 
response.addHeader( "Access-Control-Allow-Methods", "POST" ); 
response.addHeader( "Access-Control-Max-Age", "1000" );
注:可以在ajax请求中多加入一个参数:

 $.ajax({
            url: "yoururl.json",
            type: "POST",
            crossDomain: true, //这个参数--未测试
            data: data,
            dataType: "json",
            success:function(result){
                alert(JSON.stringify(result));
            },
            error:function(xhr,status,error){
                alert(status);
            }
        });

2:jsonp

ajax代码:

function registerxx(){
	var https_url_ts = "http://www.baidux.com:8080/timespacexstar/";
	var timestamp = (new Date()).valueOf(); 
	$.ajax({
		url: https_url_ts + "registerjsonp.json?timestamp=" + timestamp, //请求url
		type: "post", //http请求方式
		data:{"kaka" : "iamkaka"}, //序列化表单---data:$("#registerform").serialize(),
		async: true, //ajax请求是异步的
		dataType: "jsonp", //返回数据类型jsonp格式
		timeout: 60000, //请求超时时间
		jsonp: "jsonpcallbackfunction",//服务端用于接收callback调用的function名的参数 
		jsonpCallback: "success_jsonpCallback",//callback的function名称,服务端会把名称和data一起传递回来
		success:function(resdata){
		   var code = resdata.code;
		   var message = resdata.message;
		   var data = resdata.data;
		   alert(code + "/" + message + "/" + data);
		}
	});
}
注:页面请求的地址:

http://www.alibabax.com:8080/timespacexstar/register.html

服务器代码(spring-mvc):

import com.fasterxml.jackson.databind.util.JSONPObject;
	@ResponseBody
	@RequestMapping(value = "registerjsonp", produces = "application/json; charset=UTF-8")
	public JSONPObject registerCT(Member registerParamsC, String jsonpcallbackfunction, HttpServletRequest request){
		JsonResult json = new JsonResult();
		String kaka = request.getParameter("kaka");
		LOG.info("注册html信息数据记录111:" + jsonpcallbackfunction + " |~| " + kaka + " // " + request.getRequestURI() + "==" + request.getQueryString());
		json.setCode(JsonResult.CODE_WARMTIPS);
		json.setData("success-ok" + kaka);
		json.setMessage("successful!!!");
		JSONPObject jsonp = new JSONPObject(jsonpcallbackfunction, json);
		return jsonp;
	}

注:页面效果:



后台日志:

注册html信息数据记录111:success_jsonpCallback |~| iamkaka // /timespacexstar/registerjsonp.json==timestamp=1458791397407&jsonpcallbackfunction=success_jsonpCallback&kaka=iamkaka&_=1458791396313

3:form表单提交+target属性指向iframe中代码解析http://msdn.microsoft.com/en-us/library/ie/cc288060(v=vs.85).aspx

备注:

IE需要按照IE提供的方案使用XDomainRequest对象解决//////效果不佳

js跨域及解决方案

How to make a jsonp POST request that specifies contentType with jQuery?

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
如何设置阿里云服务器安全组?阿里云安全组规则详细解说
阿里云安全组设置详细图文教程(收藏起来) 阿里云服务器安全组设置规则分享,阿里云服务器安全组如何放行端口设置教程。阿里云会要求客户设置安全组,如果不设置,阿里云会指定默认的安全组。那么,这个安全组是什么呢?顾名思义,就是为了服务器安全设置的。安全组其实就是一个虚拟的防火墙,可以让用户从端口、IP的维度来筛选对应服务器的访问者,从而形成一个云上的安全域。
19810 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
29185 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
16459 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
20705 0
腾讯云服务器 设置ngxin + fastdfs +tomcat 开机自启动
在tomcat中新建一个可以启动的 .sh 脚本文件 /usr/local/tomcat7/bin/ export JAVA_HOME=/usr/local/java/jdk7 export PATH=$JAVA_HOME/bin/:$PATH export CLASSPATH=.
14900 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
23582 0
阿里云服务器ECS远程登录用户名密码查询方法
阿里云服务器ECS远程连接登录输入用户名和密码,阿里云没有默认密码,如果购买时没设置需要先重置实例密码,Windows用户名是administrator,Linux账号是root,阿小云来详细说下阿里云服务器远程登录连接用户名和密码查询方法
22359 0
+关注
tony~tian
追求完美,追求自由!
122
文章
2
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载