跨域问题的产生

前台调用后台接口,因为前台和后台不在同一个域内产生跨越问题。

  • 浏览器限制
  • 跨域
  • XHR(XMLHttpRequest)请求

三个条件同时产生才能发生跨域问题。

解决思路

从浏览器角度解决

使用不检查跨域的方式启动浏览器

**\chrome --disable-web-security --user-data-dir=g:\temp3

不存在任何的跨域问题,可以自由访问。

此种解决方法说明,跨域是浏览器限制的行为,跟后台没有任何的关系。

针对XHR使用JSONP访问

JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。
JSONP是一种约定,非官方框架。
前端使用代码

//每个测试用例的超时时间
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
//每个请求接口的前缀
var base = "http://localhost:8080/test";

//测试模块
describe("ajax跨域测试",function () {
    //测试方法
    it("jsonp请求",function (done) {
        //服务器返回结果
        var result;
        $.ajax({
            url: base + "/get1",dataType: "jsonp",success: function (json) {
                result = json;
            }
        });
        //由于是异步请求,需要使用setTimeout来校验
        setTimeout(function () {
            expect(result).toEqual({
                "data": "get1 ok"
            });
            //校验通过,通知jasmine框架
            done();
        },100);
    });
});

后端增加代码

package com.fwj.ajax;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice;
@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice{
    public JsonpAdvice(){
    super("callback");
    }
}

使用Jsonp后端需要做改动,需要返回非Json对象。

关于Jsonp成功的原因

  1. jsonp发送的请求是script请求,区别于xhr请求,不存在跨域的问题。
  2. 普通的xhr请求返回的是json数据对象,jsonp返回的是一个js脚本。
  3. 请求URL的不同,请求带有callback字段


    原理:jsonp请求中,对应后台中约定的callback,json代码的内容就是callback的值作为函数名,返回的的数据作为函数的参数。

JSONP弊端

  1. 服务器端需要改动。
  2. 只支持GET方法。
  3. 发送的不是XHR请求,无法使用各种XHR各种优势。

被调用方解决跨域


需要被调用方在返回中添加指定的字段,允许对方调用。

服务器端实现

被调用发-Filter解决方案。

【简单请求】:
方法为GET,HEAD,POST,并且请求header里面无自定义头,Content-Type为text/plain,multipart/form-data,application/x-www-form-urlencoded中的一种。
浏览器对于简单是先执行拿到数据再判断。

【非简单请求】:
除简单请求之外都是非简单请求。
工作中常见的非简单请求:
1. put.delete方法的ajax请求。
2. 发送json格式的ajax请求。
3. 带自定义头的ajax请求。
浏览器对于非简单请求是先发送预检命令,然后再执行

在后端增加Filter配置,在响应头中添加需要的Header。

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class CrossFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws servletexception {

    }

    @Override
    public void doFilter(ServletRequest servletRequest,ServletResponse servletResponse,FilterChain filterChain) throws IOException,servletexception {
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        HttpServletRequest request= (HttpServletRequest) servletRequest;
        String origin = request.getHeader("Origin");
        if(org.springframework.util.StringUtils.isEmpty(origin)){
            //允许所有的远程请求
            response.addheader("Access-Control-Allow-Origin","*");
        }
        String headers = request.getHeader("Access-Control-Request-Headers");
        if(org.springframework.util.StringUtils.isEmpty(headers)) {
            //允许自定义头,网页可以请求各种内容类型
            response.addheader("Access-Control-Allow-Headers",headers);
        }
         //允许所有的请求方式
        response.addheader("Access-Control-Allow-Methods","*");
        //允许OPTIONS预检命令缓存3600秒
        response.addheader("Access-Control-Max-Age","3600");
        //使Cookie生效
        response.addheader("Access-Control-Allow-Credentials","true");
        //放行
        filterChain.doFilter(servletRequest,response);
    }

    @Override
    public void destroy() {

    }
}

将此Filter加入Spring配置文件。

package com.fwj.ajax;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class AjaxApplication {

    public static void main(String[] args) {

        SpringApplication.run(AjaxApplication.class,args);
    }
    @Bean
    public FilterRegistrationBean registerFilter(){
        FilterRegistrationBean bean =new FilterRegistrationBean();
        bean.addUrlPatterns("/*");
        bean.setFilter(new CrossFilter());
        return bean;
    }
}

关于OPTIONS预检命令

OPTIONS它用于获取当前URL所支持的方法。若请求成功,则它会在HTTP头中包含一个名为“Allow”的头,值是所支持的方法,如“GET,POST”。

关于带Cookie类型的跨域

使用Cookie时”Access-Control-Allow-Methods”,不能为 *,必须使用全匹配。
Access-Control-Allow-Methods 需要为调用方的域名并且,Cookie需要存在于被调用方的域中。
并且需要设置

Access-Control-Allow-Credentials : true

前端代码如下

//测试方法
    it("getCookie请求",function (done) {
        //服务器返回结果
        var result;
        $.ajax({
            type:"get",url: base + "/getCookie",xhrFields:{
              withCredentials:true
            },100);
    });

Nginx配置

配置原理图

server{
    listen 80;
    server_name b.com;

    location/{
        proxy_pass http://localhost:8080/;

        add_header Access-Control-Allow-Methods *;
        add_header Access-Control-Max-Age 3600;
        add_header Access-Control-Allow-Credentials true;

        add_header Access-Control-Allow-Origin $http_origin;
        add_header Access-Control-Allow-Headers &http_access_control_request_headers;
        if ($request_method = OPTIONS){
            return 3600;
        }
    }
}

Nginx技巧:

//检查Nginx的配置时候正确
./Nginx -t

APACHE配置

Spring框架解决方案

在需要跨域的Controller类或者需要跨域的方法上增加注解

@CrossOrigin

调用方解决跨域

Nginx配置

使用反向代理

在调用方的Nginx上增加配置

server{
    listen 80;
    server_name a.com;
    location/{
        proxy_pass http://localhost:8081/;
    }

    location/ajaxserver{
        proxy_pass http://localhost:8080/test/;
    }
}

调用方需要访问前缀地址 “/ajaxserver”

eg:http:/a.com/ajaxserver/get1

APACHE配置

Ajax跨域问题及解决的更多相关文章

  1. 关于h5中的fetch方法解读(小结)

    这篇文章主要介绍了关于h5中的fetch方法解读(小结),fetch身为H5中的一个新对象,他的诞生,是为了取代ajax的存在而出现,有兴趣的可以了解一下

  2. ios – 使用NSURLSession获取JSON数据

    我试图从谷歌距离api使用NSURLSession获取数据,但如下所示,当我打印响应和数据时,我得到的结果为NULL.可能是什么问题?

  3. ios – 错误域= com.alamofire.error.serialization.response代码= -1011“请求失败:禁止

    任何人都可以帮我解决以下错误–>在AFNetworking2.5中使用“删除”方法时出错解决方法我发现,如果我的手机时钟不同步……它不允许我更新…也许检查你的手机设置到正确的时间“自动区”,看看是否有效…

  4. iOS网页/原生应用Facebook登录弹出 – 失败?

    如果我重新启动app/web-app,用户将自动登录,并重定向到成功页面.我认为是导致问题的原因当您在Firefox/Chrome/Safari浏览器中运行网页时,Facebook登录对话框会弹出一个弹出窗口或另一个选项卡.我相信这是这个弹出页面的一个问题,以及当成功登录时Javascript如何与自身通信.window.close的东西没有返回的根页面…失败的解决方法由于应用程序挂在前面提到的URL上,我决定在shouldStartLoadWithRequest(…)中添加if语句以强制UIWebvie

  5. ios – Watchkit新会话不起作用

    我的手表扩展中有两个视图控制器.每当我打电话时我只得到第一个视图控制器的响应,并在第二个viewcontroller中得到错误WCSession在app和watch扩展中启动.任何建议?

  6. 使用Firebase iOS Swift将特定设备的通知推送到特定设备

    我非常感谢PushNotifications的帮助.我的应用聊天,用户可以直接向对方发送短信.但是如果没有PushNotifications,它就没有多大意义.它全部设置在Firebase上.如何将推送通知从特定设备发送到特定设备?

  7. ios – 保存从查询中获取的用户的属性(即不在currentUser上)

    我有兴趣根据currentUser执行的操作将属性保存到数据库中的用户.基于以下代码,我收到错误消息“除非已通过logIn或signUp验证用户,否则无法保存用户”我想知道是否有一个解决方法,我可以将属性保存到foundUser,而无需登录该用户.谢谢你的帮助!解决方法如果要更新当前不是登录用户的用户,则需要使用主密钥调用Parse.您可以从CloudCode执行此操作;并从您的iOS项目中调用它;

  8. 在iOS中使用NSJSONSerialization进行JSON解析

    解决方法首先在您的JSON响应字典中,在“RESPONSE”键下,您有一个数组而不是字典,该数组包含字典对象.所以要提取用户名和电子邮件ID,如下所示

  9. Xcode:Alamofire获得String响应

    我是IOS开发的新手,目前正在与Alamofire学习网络我正在尝试登录…每当凭证正确时,.PHP文件返回一个json,我可以通过以下代码从Alamofire获取json:现在……当凭证错误时,.PHP不会给json..而且它返回一个字符串..例如“wrong_password”或“userLocked”等等……如何通过Alamofire获得String响应?解决方法如果您希望JSON响应使用.responseJSON,如果您想要String响应,请使用.responseString.如果你想两者同时使用

  10. ios – 全局变量中的Appdelegate in swift

    我将一些数据从viewcontroller&从另一个视图控制器获取它.下面是应用程序委托的代码代码设置mainDic代码来获取字典.问题是我得到的输出没有.请让我正确.解决方法这是你的错误尝试将您的代码更改为此

随机推荐

  1. xe-ajax-mock 前端虚拟服务

    最新版本见Github,点击查看历史版本基于XEAjax扩展的Mock虚拟服务插件;对于前后端分离的开发模式,ajax+mock使前端不再依赖后端接口开发效率更高。CDN使用script方式安装,XEAjaxMock会定义为全局变量生产环境请使用xe-ajax-mock.min.js,更小的压缩版本,可以带来更快的速度体验。

  2. vue 使用 xe-ajax

    安装完成后自动挂载在vue实例this.$ajaxCDN安装使用script方式安装,VXEAjax会定义为全局变量生产环境请使用vxe-ajax.min.js,更小的压缩版本,可以带来更快的速度体验。cdnjs获取最新版本点击浏览已发布的所有npm包源码unpkg获取最新版本点击浏览已发布的所有npm包源码AMD安装require.js安装示例ES6Module安装通过Vue.use()来全局安装示例./Home.vue

  3. AJAX POST数据中文乱码解决

    前端使用encodeURI进行编码后台java.net.URLDecoder进行解码编解码工具

  4. Koa2框架利用CORS完成跨域ajax请求

    实现跨域ajax请求的方式有很多,其中一个是利用CORS,而这个方法关键是在服务器端进行配置。本文仅对能够完成正常跨域ajax响应的,最基本的配置进行说明。这样OPTIONS请求就能够通过了。至此为止,相当于仅仅完成了预检,还没发送真正的请求呢。

  5. form提交时,ajax上传文件并更新到<input>中的value字段

  6. ajax的cache作用

    filePath="+escape;},error:{alert;}});解决方案:1.加cache:false2.url加随机数正常代码:网上高人解读:cache的作用就是第一次请求完毕之后,如果再次去请求,可以直接从缓存里面读取而不是再到服务器端读取。

  7. 浅谈ajax上传文件属性contentType = false

    默认值为contentType="application/x-www-form-urlencoded".在默认情况下,内容编码类型满足大多数情况。在这里,我们主要谈谈contentType=false.在使用ajax上传文件时:在其中先封装了一个formData对象,然后使用post方法将文件传给服务器。说到这,我们发现在JQueryajax()方法中我们使contentType=false,这不是冲突了吗?这就是因为当我们在form标签中设置了enctype=“multipart/form-data”,

  8. 909422229_ajaxFileUpload上传文件

    ajaxFileUpload.js很多同名的,因为做出来一个很容易。我上github搜AjaxFileUpload出来很多类似js。ajaxFileUpload是一个异步上传文件的jQuery插件传一个不知道什么版本的上来,以后不用到处找了。语法:$.ajaxFileUploadoptions参数说明:1、url上传处理程序地址。2,fileElementId需要上传的文件域的ID,即的ID。3,secureuri是否启用安全提交,默认为false。4,dataType服务器返回的数据类型。6,error

  9. AJAX-Cache:一款好用的Ajax缓存插件

    原文链接AJAX-Cache是什么Ajax是前端开发必不可少的数据获取手段,在频繁的异步请求业务中,我们往往需要利用“缓存”提升界面响应速度,减少网络资源占用。AJAX-Cache是一款jQuery缓存插件,可以为$.ajax()方法扩展缓存功能。

  10. jsf – Ajax update/render在已渲染属性的组件上不起作用

    我试图ajax更新一个有条件渲染的组件。我可以确保#{user}实际上是可用的。这是怎么引起的,我该如何解决呢?必须始终在ajax可以重新呈现之前呈现组件。Ajax正在使用JavaScriptdocument.getElementById()来查找需要更新的组件。但是如果JSF没有将组件放在第一位,那么JavaScript找不到要更新的内容。解决方案是简单地引用总是渲染的父组件。

返回
顶部