跨域对接方法总结

一、后台跨域-V1

1. 后台设置

  1. 配置过滤器,为所有的响应头都加上 下面四个字段
  • Access-Control-Allow-Origin: '具体源' :允许通过跨域访问后台服务器的源。如果需要使用section来标示不同的会话,则需要前端设置允许cookie(因为浏览器是通过发送cookie中相关的ID ( JSESSIONID )来标识的),并且后台的 Access-Control-Allow-Origin 不可以设置为通配符 ‘ * ’,需要指定一个明确的域名,可以是 null (即通过本地文件 file:// 发送的请求), 然后后台动态的获取request 的 origin 去设置 Access-Control-Allow-Origin 。

  • Access-Control-Allow-Methods: "POST, ..." :该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法

  • Access-Control-Allow-Headers: "Content-Type, ...":该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段

  • Access-Control-Max-Age: '3600':规定在多长时间内不需要再发生 预检请求 就能跨域访问

// spring 写法

package gdut.qg.utils;

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

/**
* Created by logan on 2017/5/23.
*/
public class CORSFilter implements Filter {
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        String Origin = request.getHeader("Origin");
    /* 此处通过动态设置运行跨域访问的源 */
        response.setHeader("Access-Control-Allow-Origin", Origin);
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "36000");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.addHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        chain.doFilter(req, res);
        
    }
    public void init(FilterConfig filterConfig) {}
    public void destroy() {}
}

2. 前端设置

  1. 如果需要保持将两次请求维持在同一个会话中(即后台需要用到 session 来识别用户),需要保持Request Cookies 中的 JSESSIONID 的值在两次请求中不变,即需要在请求时允许跨域请求携带 Cookie
  • 原生
//原生

var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.withCredentials = true;      //允许跨域请求携带 Cookie
xhr.send();
  • jQuery
// jQuery

$.ajax({
    type: "post",
    url: "xxx",
    data: data,
    xhrFields: {
        withCredentials: true       //允许跨域请求携带 Cookie
    }
    success: function(data) {
        console.log(data)
    },
});

二、后台跨域-V2

1. 后台设置

  1. 配置过滤器,为所有的响应头都加上 下面的字段
  • Access-Control-Allow-Origin: ' * ' :允许通过跨域访问后台服务器的源,如果设置为 * ,表示可以让任何源访问,当是这里需要再设置一个参数 Access-Control-Allow-Credentials 为 false,表明不允许携带 cookie 才可以

  • Access-Control-Allow-Methods: "POST, ..." :该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法

  • Access-Control-Allow-Headers: "Content-Type, ...":该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段

  • Access-Control-Max-Age: '3600':规定在多长时间内不需要再发生 预检请求 就能跨域访问

  • Access-Control-Allow-Credentials : false : 不允许携带 cookie

2. 前端设置

  1. 设置 withCredentials 为 false
// jQuery

$.ajax({
    type: "post",
    url: "xxx",
    data: data,
    xhrFields: {
    withCredentials: false       //不允许跨域请求携带 Cookie
    }
    success: function(data) {
        console.log(data)
    },
});

// axios

import axios from 'axios'
axios.defaults.withCredentials = false    //全局设置 withCredentials 为 false
export const IP = 'https://xxxxxxx.com/';  
export const myAxios = axios.create({
    baseURL: IP,
})

3. 缺点

  1. 由于不允许传cookie,所以无法把 section 通过 cookie 传到服务器,即后台获取不到section。所以无法记住登录状态,需要改为用 token 才行。

三、插件跨域

使用Google插件 :Allow-Control-Allow-Origin: *

1. 后台

不需要后台配置任何的响应头字段

2. 前端

直接写要访问的其他域的路径,跟平时使用没有区别。

3. 缺点

  1. 插件跨域后相当于在不同的会话框中,所以没有包含之前登录的 section,即后台获取不到section。

  2. 该插件会将请求的 origin 设置为 ”http: //evil.com“。

// 这是请求头携带的信息
Request Headers                               
    OPTIONS /ExcellentCourses/admin/login HTTP/1.1
    Host: 123.207.228.117
    Connection: keep-alive
    Access-Control-Request-Method: POST
    Origin: http://evil.com/                      //注意这里的origin已经被插件换了
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)...
    Access-Control-Request-Headers: content-type
    Accept: */*
    Accept-Encoding: gzip, deflate, sdch
    Accept-Language: zh-CN,zh;q=0.8

四、代理跨域

1. 前端

  1. 如果使用Vue框架,可以使用 Vue-cli 的 proxyTable 配置
    proxyTable: {
        '/api': {
            target: 'http://192.168.1.107:80',
            changeOrigin: true,
            pathRewrite: {
                '^/api': '/'
            }
        }
    },
    // 把含有 api 的请求路径代理到 http://192.168.1.107:80/ 上。
    //如 localhost:8080/api/add -> http://192.168.1.107:80/add

可配置 axios 来食用

import axios from 'axios'

IP = '/api';

myAxios = axios.create({
	baseURL: IP
})
	
getAllTeachers() {
    return new Promise((resolve, reject) => {
        myAxios({
            method: 'POST',
            url: '/teacher/allTeachers'
        }).then(function(res){
            resolve(res.data)
        }).catch(function(err){
            reject(err)
        })
    })
}

2. 后台

  1. 不需要后台配置任何的响应头字段

  2. session仍然可以使用

五、总结

  1. 使用第一种可以用到真实的线上环境,第二中可以配合token在真实线上使用,而第三种和第四种只是用于开发环境

  2. 如果后台不需要使用 section,并且之后整合前后代码是在同一个服务器上,则推荐使用第二种方式,因为这样前后都不要修该自己的代码,能缩短开发周期。

  3. 如果后台需要用到 section,并且之后整合前后代码是在同一个服务器上,则推荐使用第四种方式,前提是前端能使用 webpack 来配置代理服务器

  4. 如果需要跨域而前端又不能使用代理,则需要前后一起去配置有关CORS的请求头和响应头信息,不过这种方法当真正上线时也可以跨域,算是正统的方法。

六、参考

  1. 关于简单请求与非简单请求的跨域问题。跨域资源共享 CORS 详解
  2. 后台实现跨越。Spring MVC通过CROS协议解决跨域问题
  3. 跨域请求,关于后端session会话丢失的解决办法
  4. 浏览器 AJAX 跨域请求访问控制
posted @ 2018-03-15 00:33  另一个小菜头  阅读(551)  评论(0编辑  收藏  举报