转:https://blog.csdn.net/csdn_ds/article/category/6937392/3

在工作中,大家应该都遇到过ajax跨域问题,浏览器的错误如下:

XMLHttpRequest cannot load http://目标地址No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://当前页面地址'  is therefore not allowed access.

为什么会出现跨域问题

跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制。

在此说明一下,所谓的同源,指的是域名、协议、端口均相等。举例如下:

http://www.abc.com/a/b 调用 http://www.abc.com/d/c(非跨域)

http://www.abc.com/a/b 调用 http://www.def.com/d/c (跨域:域名不一致)

http://www.abc.com:81/a/b 调用 http://www.abc.com:82/d/c (跨域:端口不一致)

http://www.abc.com/a/b 调用 https://www.abc.com/d/c (跨域:协议不同)

请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。

在一个http请求中,http头部Referer或Origin字段标识了当前域名,Host字段标识了此时请求的域名。

故,如果我们在当前的js页面,通过ajax请求第三方的数据,就会出现浏览器的跨域问题。

解决跨域问题

解决跨域问题,有如下三种方式:

1、使用jsonp

2、服务器代理

3、在服务端设置response header中Access-Control-Allow-Origin字段。

使用jsonp

jsonp解决跨域问题的原理是,浏览器的script标签是不受同源策略限制的,我们可以在script标签中访问任何域名下的资源文件。利用这一特性,用script标签从服务器中请求数据,同时服务器返回一个带有方法和数据的js代码,请求完成,调用本地的js方法,来完成数据的处理。

前端实现,以Jquery的ajax方法为例:

  1.  
    $.ajax({
  2.  
    url:"",
  3.  
    dataType:'jsonp',
  4.  
    data:'',
  5.  
    jsonp:'callback', //传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(默认为:callback)
  6.  
     
  7.  
    success:function(result) {
  8.  
    //成功的处理
  9.  
    },
  10.  
    error:function(){
  11.  
    //错误处理
  12.  
    }
  13.  
    });

服务端此时返回的不能是普通的json字符串,而是一段可以被前端js执行的一段js代码。

比较一下json与jsonp格式的区别:

json格式:

  1.  
    {
  2.  
    "message":"获取成功",
  3.  
    "state":"1",
  4.  
    "result":{"name":"工作组1","id":1,"description":"11"}
  5.  
    }

jsonp格式:

  1.  
    callback({
  2.  
    "message":"获取成功",
  3.  
    "state":"1",
  4.  
    "result":{"name":"工作组1","id":1,"description":"11"}
  5.  
    })

从格式来看,jsonp是在json的基础上包装了一个方法名,此方法名是前端请求传过来的,如请求地址为:http://localhost:9999/tookApp/tbk/getItem?callback=JSONP_CALLBACK,那么方法名就是JSONP_CALLBACK。

下面提供一段java代码,对象转jsonp的工具类:

  1.  
    package com.tooklili.app.web.util;
  2.  
     
  3.  
    import javax.servlet.http.HttpServletRequest;
  4.  
     
  5.  
    import org.apache.commons.lang.StringUtils;
  6.  
    import org.springframework.web.context.request.RequestContextHolder;
  7.  
    import org.springframework.web.context.request.ServletRequestAttributes;
  8.  
     
  9.  
    import com.fasterxml.jackson.databind.util.JSONPObject;
  10.  
     
  11.  
    /**
  12.  
    *
  13.  
    * @author ding.shuai
  14.  
    * @date 2016年8月15日上午9:47:02
  15.  
    */
  16.  
    public class AppUtil {
  17.  
     
  18.  
    /**
  19.  
    * 判断json字符串是否需要转化成jsonp格式
  20.  
    * @param request
  21.  
    * @param result
  22.  
    * @return
  23.  
    */
  24.  
    public static Object conversionJsonp(Object result){
  25.  
    HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
  26.  
    return conversionJsonp(request, result);
  27.  
    }
  28.  
     
  29.  
     
  30.  
    public static Object conversionJsonp(HttpServletRequest request,Object result){
  31.  
    String callback = request.getParameter("callback");
  32.  
    if(StringUtils.isNotEmpty(callback)){
  33.  
    return new JSONPObject(callback, result);
  34.  
    }
  35.  
    return result;
  36.  
    }
  37.  
    }

jsonp的缺点:

1、JSONP是一种非官方的方法,而且这种方法只支持GET方法,不如POST方法安全。(从实现机制就可明白)。

2、JSONP的实现需要服务器配合,如果是访问的是第三方的服务器,我们没有修改服务器的权限,那么这种方式是不可行的。

服务器代理

这种方式运用的就是服务器的反向代理技术,控制客户端和服务器的访问都从代理服务器经过,比如用nginx作为服务器代理,在nginx上配置客户端和第三方服务的反向代理,这样就可保证客户端、第三方是同源的了,同一个源,都来自代理服务器。

关于nginx的反向代理配置,可访问我的这篇博客:http://blog.csdn.net/csdn_ds/article/details/58605591

服务器代理的缺点:

开发比较麻烦,对开发环境比较严格,需要在本机上配置代理服务器。

优点:

完美解决使用jsonp,第三方服务没有修改权限的问题。程序的代码侵入性小,代码级别不需要考虑跨域问题。

在服务端设置response headerAccess-Control-Allow-Origin字段

在被请求的Response Header中加入如下代码:

  1.  
    // 指定允许其他域名访问
  2.  
    response.setHeader("Access-Control-Allow-Origin", "*");
  3.  
    // 响应类型
  4.  
    response.setHeader("Access-Control-Allow-Methods", "POST");
  5.  
    // 响应头设置
  6.  
    response.setHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");

如果所有请求都想让其他域名的服务通过浏览器ajax请求到,可以通过Filter统一设置response header。

  1.  
    package com.tooklili.app.web.filter;
  2.  
     
  3.  
    import java.io.IOException;
  4.  
     
  5.  
    import javax.servlet.Filter;
  6.  
    import javax.servlet.FilterChain;
  7.  
    import javax.servlet.FilterConfig;
  8.  
    import javax.servlet.ServletException;
  9.  
    import javax.servlet.ServletRequest;
  10.  
    import javax.servlet.ServletResponse;
  11.  
    import javax.servlet.http.HttpServletResponse;
  12.  
     
  13.  
    /**
  14.  
    * 设置公共属性的过滤器
  15.  
    * @author shuai.ding
  16.  
    *
  17.  
    * @date 2017年6月21日上午11:02:27
  18.  
    */
  19.  
    public class CommonSetFilter implements Filter{
  20.  
     
  21.  
    @Override
  22.  
    public void init(FilterConfig filterConfig) throws ServletException {
  23.  
    }
  24.  
     
  25.  
    @Override
  26.  
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
  27.  
    throws IOException, ServletException {
  28.  
    //解决跨域问题
  29.  
    HttpServletResponse httpServletResponse =(HttpServletResponse)response;
  30.  
    // 指定允许其他域名访问
  31.  
    httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
  32.  
    // 响应类型
  33.  
    httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST");
  34.  
    // 响应头设置
  35.  
    httpServletResponse.setHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
  36.  
     
  37.  
    chain.doFilter(request, response);
  38.  
    }
  39.  
     
  40.  
    @Override
  41.  
    public void destroy() {
  42.  
    }
  43.  
     
  44.  
    }

此处说明一下,笔者亲测:只设置Access-Control-Allow-Origin属性也是可以的。

Access-Control-Allow-Origin:* 表示允许任何域名跨域访问

如果需要指定某域名才允许跨域访问,只需把Access-Control-Allow-Origin:*改为Access-Control-Allow-Origin:允许的域名

例如:response.setHeader(“Access-Control-Allow-Origin”,”http://www.client.com”);

缺点:

1、此种解决跨域方案,需要浏览器支持H5,因为这是HTML5解决跨域的方式,如果产品面向的是PC端,这种方式可能就不是一个好的解决方案,如果面向的是手机端,此方法不为一个简单、粗暴的好方式。

2、设置*,存在安全隐患。

总结

综上三种解决跨域的方案,个人感觉使用服务代理最好,没有破坏浏览器的安全策略,但这个对开发环境要高一点。设置response header的方式,根据具体情况分析,要考虑清楚产品面向的用户。对于jsonp这种方式,虽然没有破坏浏览器的安全策略,但只支持get方式的请求,有点不能接受,因为get传输有参数长度的限制,同时又要考虑传输中文的乱码问题,但如果项目中只是简单的查询、展示,这种方式还是可以考虑的。

其他好文推荐:

Access-Control-Allow-Origin 跨域设置多域名:http://www.jianshu.com/p/b587dd1b7086

ajax跨域问题以及解决方案的更多相关文章

  1. ajax 跨域访问的解决方案

    ajax 跨域访问的解决方案 一.什么是跨域: 1.什么样的请求属于跨域: 域名,端口有任何一个不相同都属于跨域: 二.跨域的常用几种解决方案: 1.jsonp: 2.iframe: 3.webcon ...

  2. Ajax跨域问题及解决方案 asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS) c#中的Cache缓存技术 C#中的Cookie C#串口扫描枪的简单实现 c#Socket服务器与客户端的开发(2)

    Ajax跨域问题及解决方案   目录 复现Ajax跨域问题 Ajax跨域介绍 Ajax跨域解决方案 一. 在服务端添加响应头Access-Control-Allow-Origin 二. 使用JSONP ...

  3. PHP Ajax 跨域问题最佳解决方案 【摘自菜鸟教程】

    PHP Ajax 跨域问题最佳解决方案 分类 编程技术 http://www.runoob.com/w3cnote/php-ajax-cross-border.html 本文通过设置Access-Co ...

  4. ajax跨域原理以及解决方案

    说明 跨域主要是由于浏览器的“同源策略”引起,分为多种类型,本文主要探讨Ajax请求跨域问题 前言 强烈推荐阅读参考来源中的文章,能够快速帮助了解跨域的原理 参考来源 本文参考了以下来源 浏览器同源政 ...

  5. [转载]JQuery的Ajax跨域请求的解决方案

    今天在项目中需要做远程数据加载并渲染页面,直到开发阶段才意识到ajax跨域请求的问题,隐约记得Jquery有提过一个ajax跨域请求的解决方式,于是即刻翻出Jquery的API出来研究,发现JQuer ...

  6. ajax跨域访问的解决方案

    今天的工作中要访问摄像机内部的一个web站点,这就涉及到jquery的ajax跨域访问的问题.我使用的是jquery1.7的版本,下面总结如下: 问题一:一开始用IE调试,总是返回No Transpo ...

  7. 有关Ajax跨域请求的解决方案

    前言 最近博主在赶项目进度.所以微信二次开发那边的博文一直没有更新.后续时间会慢慢记录这个学习历程的.来年公司要开发微信小程序.到时也会记录一下历程. 闲话少说,今天在工作中遇到了SpringMVC接 ...

  8. Ajax跨域问题及解决方案

    目录 复现Ajax跨域问题 Ajax跨域介绍 Ajax跨域解决方案 一. 在服务端添加响应头Access-Control-Allow-Origin 二. 使用JSONP解决 小结 复现Ajax跨域问题 ...

  9. ajax跨域请求的解决方案

    一直打算改造一下自己传统做网站的形式. 我是.Net程序员,含辛茹苦数年也没混出个什么名堂. 最近微信比较火, 由于现在大环境的影响和以前工作的总结和经验,我打算自己写一个数据,UI松耦合的比较新潮的 ...

随机推荐

  1. 导航页的开发--手机web app开发笔记

    好了,的所有的基础知识已经准备完毕了,现在开始制作引导页.这个引导页需要一个HTML文件,JS文件,一个CSS文件.在HBuilderX中根目录下添加“Guid.html”,在JS文件夹添加“myth ...

  2. Mysql死锁如何排查:insert on duplicate死锁一次排查分析过程

    前言 遇到Mysql死锁问题,我们应该怎么排查分析呢?之前线上出现一个insert on duplicate死锁问题,本文将基于这个死锁问题,分享排查分析过程,希望对大家有帮助. 死锁案发还原 表结构 ...

  3. Java NIO 上

    概述: NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector. 传统IO基于字节流和字符流进行操作,而NIO基于Channel和Buffer(缓冲区)进行操作, ...

  4. HZNU Training 4 for Zhejiang Provincial Collegiate Programming Contest 2019

    今日这场比赛我们准备的题比较全面,二分+数论+最短路+计算几何+dp+思维+签到题等.有较难的防AK题,也有简单的签到题.为大家准备了一份题解和AC代码. A - Meeting with Alien ...

  5. codeforces 814 C. An impassioned circulation of affection(二分+思维)

    题目链接:http://codeforces.com/contest/814/problem/C 题意:给出一串字符串然后q个询问,问替换掉将m个字符替换为字符c,能得到的最长的连续的字符c是多长 题 ...

  6. CF980C Posterized 贪心 二十五

    Posterized time limit per test 1 second memory limit per test 256 megabytes input standard input out ...

  7. .Net Core WebApi简单创建及使用

    按照目前的软件开发发展趋势中,不管是前后端分离还是提供数据服务,WebApi使用的越来越广泛,而且.NET Core也是我们.NET开发人员未来发展的趋势,所以说学会使用.NET Core Api是非 ...

  8. 【Offer】[39] 【数组中出现次数超过一半的数字】

    题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如,输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数 ...

  9. eclipse的properties文件中文被转码问题

    如图所示:首次在properties里打中文注释,结果一输入中文就自动被转码,于是查看了一下项目的编码是UTF-8的,而eclipse中默认的properties文件编码是ISO的,所以修改一下即可 ...

  10. 【LeetCode】56-合并区间

    题目描述 给出一个区间的集合,请合并所有重叠的区间. 示例 1: 输入: [[1,3],[2,6],[8,10],[15,18]] 输出: [[1,6],[8,10],[15,18]] 解释: 区间 ...