AJAX跨域

一、什么是AJAX跨域问题、产生AJAX跨域问题的原因

什么是AJAX跨域问题

  • 简单来说,就是前端调用后端服务接口时
  • 如果服务接口不是同一个域,就会产生跨域问题

AJAX跨域场景

  • 前后端分离、服务化的开发模式
  • 前后端开发独立,前端需要大量调用后端接口的场景
  • 只要后端接口不是同一个域,就会产生跨域问题
  • 跨域问题很普遍,解决跨域问题也很重要

AJAX跨域原因

  • 浏览器限制:浏览器安全校验限制
  • 跨域(协议、域名、端口任何一个不一样都会认为是跨域)
  • XHR(XMLHttpRequest)请求

二、AJAX跨域解决方式

AJAX跨域问题解决思路

  • 浏览器:浏览器取下跨域校验,实际价值不大
  • XHR:不使用XHR,使用JSONP,有很多弊端,无法满足现在的开发要求
  • 跨域:被调用方修改支持跨域调用(指定参数);调用方修改隐藏跨域(基于代理)

1、禁止浏览器检查

cmd启动的时候添加参数关闭安全检测

--disable-web-security --user-data-dir=C:MyChromeDevUserData

2、JSONP

package com.xjn.ajax.server.controller;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice;

/**
 * <br>
 * 标题: JSONP 全局处理<br>
 * 描述: 统一处理JSONP<br>
 */
@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice{
    public JsonpAdvice() {
        // 与前端约定好回调方法名称,默认是callback
        super("callback");
    }
}
            $.ajax({
                url: base + "/get1",
                dataType: "jsonp",
                jsonp:"callback",
                success: function (res) {
                    result = res;
                }
            });

jsonp实际原理是在url后面拼接一串字符,使浏览器知道自己是jsonp请求。所以仅适用于get方法请求,后端返回来的数据经过jsonpadvice配置,返回的是javascript数据。

3、支持跨域

方法一:被调用方支持跨域

被调用方解决,基于支持跨域的解决思路,基于Http协议关于跨域的相关规定,在响应头里增加指定的字段告诉浏览器,允许调用跨域请求是直接从浏览器发送到被调用方,被调用方在响应头里增加相关信息,返回到页面,页面能正常获取请求内容。

过滤器java代码

import org.springframework.util.StringUtils;

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

/**
 * <br>
 * 标题: 服务端解决跨域<br>
 * 描述: 使用Filter<br>
 *
 * @author zc
 * @date 2018/04/18
 */
public class CrosFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse res = (HttpServletResponse)response;

        HttpServletRequest req = (HttpServletRequest)request;

        // 支持所有域
        String origin = req.getHeader("Origin");
        if (!StringUtils.isEmpty(origin)){
            // 支持任何域名的跨域调用 且 支持带cookie(是被调用方域名的cookie,而不是调用方的cookie)
            res.addHeader("Access-Control-Allow-Origin",origin);
        }
        // 指定允许的域,带cookie时,origin必须是全匹配,不能使用 *
//        res.addHeader("Access-Control-Allow-Origin","http://localhost:8081");
        // 允许所有域,但不能满足带 cookie 的跨域请求
//        res.addHeader("Access-Control-Allow-Origin","*");

        // 支持所有自定义头
        String headers = req.getHeader("Access-Control-Allow-Headers");
        if (!StringUtils.isEmpty(headers)){
            // 允许所有header
            res.addHeader("Access-Control-Allow-Headers",headers);
        }
        // 允许所有header
//        res.addHeader("Access-Control-Allow-Headers","*");

        // 指定允许的方法
//        res.addHeader("Access-Control-Allow-Methods","GET");
        // 允许所有方法
        res.addHeader("Access-Control-Allow-Methods","*");
        // 允许浏览器在一个小时内,缓存跨域访问信息(即上面三个信息)
        res.addHeader("Access-Control-Max-Age","3600");
        // 启用 cookie
        res.addHeader("Access-Control-Allow-Credentials","true");

        chain.doFilter(request,response);
    }

    @Override
    public void destroy() {

    }
}

web.xml中配置注册过滤器 (1)

<filter>
    <filter-name>CrossFilter</filter-name>
    <filter-class>com.test.ajax.cross.filter.CrossFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CrossFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

javabean方式配置过滤器

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * <br>
 * 标题: 配置类<br>
 * 描述: 注册CrosFilter<br>
 */
@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean registrationBean(){
        FilterRegistrationBean filter = new FilterRegistrationBean();
        filter.addUrlPatterns("/*");
        filter.setFilter(new CrosFilter());
        return filter;
    }
}

跨域携带cookie

    function getCookie(){
         $.ajax({
             url: "http://localhost:8080/test-ajax-cross/test/getCookie",
             xhrFields:{
                 // 带上证书,发送 AJAX 请求时带上 cookie
                 withCredentials:true
             },
             // 允许跨域
             crossDomain: true,
             success:function(result){
                 console.log(result);
                 $("body").append("<br>" + JSON.stringify(result));
             }
         });

简单请求与非简单请求

  • 简单请求:浏览器先发送真正的请求后检查
  • 请求方法:GET、HEAD、POST的一种
  • 请求header:无自定义header;Content-Type为:text/plain、multipart/form-data、application/x-www-form-urlencoded的一种
  • 非简单请求:浏览器先发预检命令,检查通过后,才发送真正的请求
  • 常见的有:PUT、DELETE
  • 其它条件:发送Json格式的请求、带自定义header的请求
  • 预检命令:浏览器检测到跨域请求, 会自动发出一个OPTIONS请求, 就是所谓的预检(preflight)请求。当预检请求通过的时候,才发送真正的请求。

另外可以对被调用方的apache服务器、nginx服务器进行配置跨域

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。cors是浏览器直接访问被调用方服务器。

4、隐藏跨域

使用Nginx反向代理实现

  • 修改主机hosts文件增加映射本地域名:127.0.0.1 a.com
  • 在vhost目录下创建a.com.conf
  • 启动niginx,访问a.com/ajaxserver/get1

编写a.com.conf

server{
    listen 80;
    server_name a.com;

    location /{
         proxy_pass http://localhost:8081/;
    }

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

}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值