欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SpringBoot:处理跨域请求

程序员文章站 2022-06-20 23:08:34
一、跨域背景 1.1 何为跨域? 的一般格式: 示例: 是由 + + + + 组成。 只要协议,子域名,主域名,端口号这四项组成部分中有一项不同,就可以认为是不同的域,不同的域之间互相访问资源,就被称之为跨域。 1.2 一次正常的请求 Controller层代码: 启动项目,测试请求 浏览器打开 " ......

一、跨域背景

1.1 何为跨域?

url的一般格式:

协议 + 域名(子域名 + 主域名) + 端口号 + 资源地址

示例:

https://www.dustyblog.cn:8080/say/hello 是由

https + www + dustyblog.cn + 8080 + say/hello
组成。

只要协议,子域名,主域名,端口号这四项组成部分中有一项不同,就可以认为是不同的域,不同的域之间互相访问资源,就被称之为跨域。

1.2 一次正常的请求

  • controller层代码:
@requestmapping("/demo")
@restcontroller
public class corstestcontroller {

    @getmapping("/sayhello")
    public string sayhello() {
        return "hello world !";
    }
}
  • 启动项目,测试请求

浏览器打开localhost:8080/demo/sayhello

可以打印出“hello world”

1.3 跨域测试

以chrome为例:

  • 打开任意网站,如:

  • 按f12,打开【开发者工具】,在里面的【console】可以直接输入js代码测试;

var token= "ltsfvqkxvps1nparxs2lpus2q2ipgstidmrs8zmhnv3rt7rknhln6d2ffirkvezvieexgehgi/ptnyngqjzlygkja4+zyixxtdmok/n+ab6wtsskyxereh3ar8kwerwirvx+uofveh3dgmdw1347syjbl/ilgkx5xkozcbfb1f0=,lzkg22zbnsuohagauapebn541x5ohuk7rlvnhshwdm/ba4dcip1f/3bnu4gaelqu6cds/0fg9li5csphe8pyhr1ii/tncuyxqhmf9bhyd6ugwoftfvlmtp6rdopvrpg24rsjjbwy2kuoojjk5uv6futmbrstvobezaxykzmm2m4=,r4qed2psvrtr8tkbtjnnfubw+yr4di+gtogjwyer7qzk9hlduvllzuseepwjtbpz+uurvmplin5wm9ge29ft5as4okddplih8kwnis9y3r9tgh3mnsutgrgayanniy9ji5wnziz9ce2cfzlxoyuzxocsvfoxuw70ty0uklvm/78=";
var xhr = new xmlhttprequest();
xhr.open('get', 'http://127.0.0.1:8080/demo/sayhello');
xhr.setrequestheader("x-access-token",token);
xhr.send(null);
xhr.onload = function(e) {
    var xhr = e.target;
    console.log(xhr.responsetext);
}
  • 输入完后直接按回车键就可以返回结果:
access to xmlhttprequest at 'http://127.0.0.1:8080/demo/sayhello' 
from origin 'https://blog.csdn.net' has been blocked by cors policy: 
no 'access-control-allow-origin' header is present on the requested resource.

该结果表明:该请求在https://blog.csdn.net域名下请求失败!

二、解决方案 - cors跨域

2.1 cors是什么

cors全称为cross origin resource sharing(跨域资源共享), 每一个页面需要返回一个名为access-control-allow-origin的http头来允许外域的站点访问,你可以仅仅暴露有限的资源和有限的外域站点访问。

我们可以理解为:如果一个请求需要允许跨域访问,则需要在http头中设置access-control-allow-origin来决定需要允许哪些站点来访问。如假设需要允许这个站点的请求跨域,则可以设置:

access-control-allow-origin:https://www.dustyblog.cn。

2.2 方案一:使用@crossorigin注解

2.2.1 在controller上使用@crossorigin注解

该类下的所有接口都可以通过跨域访问

@requestmapping("/demo2")
@restcontroller
//@crossorigin //所有域名均可访问该类下所有接口
@crossorigin("https://blog.csdn.net") // 只有指定域名可以访问该类下所有接口
public class corstest2controller {

    @getmapping("/sayhello")
    public string sayhello() {
        return "hello world --- 2";
    }
}

这里指定当前的corstest2controller中所有的方法可以处理https://csdn.net域上的请求,这里可以测试一下:

  • 在页面打开调试窗口,输入(注意:这里请求地址是/demo2,请区别于1.2 案例中的/demo)
var token= "ltsfvqkxvps1nparxs2lpus2q2ipgstidmrs8zmhnv3rt7rknhln6d2ffirkvezvieexgehgi/ptnyngqjzlygkja4+zyixxtdmok/n+ab6wtsskyxereh3ar8kwerwirvx+uofveh3dgmdw1347syjbl/ilgkx5xkozcbfb1f0=,lzkg22zbnsuohagauapebn541x5ohuk7rlvnhshwdm/ba4dcip1f/3bnu4gaelqu6cds/0fg9li5csphe8pyhr1ii/tncuyxqhmf9bhyd6ugwoftfvlmtp6rdopvrpg24rsjjbwy2kuoojjk5uv6futmbrstvobezaxykzmm2m4=,r4qed2psvrtr8tkbtjnnfubw+yr4di+gtogjwyer7qzk9hlduvllzuseepwjtbpz+uurvmplin5wm9ge29ft5as4okddplih8kwnis9y3r9tgh3mnsutgrgayanniy9ji5wnziz9ce2cfzlxoyuzxocsvfoxuw70ty0uklvm/78=";
var xhr = new xmlhttprequest();
xhr.open('get', 'http://127.0.0.1:8080/demo2/sayhello');
xhr.setrequestheader("x-access-token",token);
xhr.send(null);
xhr.onload = function(e) {
    var xhr = e.target;
    console.log(xhr.responsetext);
}

返回结果:

ƒ (e) {
    var xhr = e.target;
    console.log(xhr.responsetext);
}
vm156:8 hello world --- 2

说明跨域成功!

  • 换个域名测试一下看跨域是否还有效,在按照上述方法测试一下,返回结果:
options http://127.0.0.1:8080/demo2/sayhello 403
(anonymous)
access to xmlhttprequest at 'http://127.0.0.1:8080/demo2/sayhello' 
from origin 'http://www.cnblogs.com' has been blocked by cors policy: 
response to preflight request doesn't pass access control check: 
no 'access-control-allow-origin' header is present on the requested resource.

说明跨域失败!证明该方案成功指定了部分域名能跨域!

2.3 方案二:cors全局配置-实现webmvcconfigurer

  • 新建跨域配置类:corsconfig.java:
/**
 * 跨域配置
 */
@configuration
public class corsconfig implements webmvcconfigurer {

    @bean
    public webmvcconfigurer corsconfigurer()
    {
        return new webmvcconfigurer() {
            @override
            public void addcorsmappings(corsregistry registry) {
                registry.addmapping("/**").
                        allowedorigins("https://www.dustyblog.cn"). //允许跨域的域名,可以用*表示允许任何域名使用
                        allowedmethods("*"). //允许任何方法(post、get等)
                        allowedheaders("*"). //允许任何请求头
                        allowcredentials(true). //带上cookie信息
                        exposedheaders(httpheaders.set_cookie).maxage(3600l); //maxage(3600)表明在3600秒内,不需要再发送预检验请求,可以缓存该结果
            }
        };
    }
}
  • 测试,在允许访问的域名控制台输入(注意,这里请求的是http://127.0.0.1:8080/demo3):
var token= "ltsfvqkxvps1nparxs2lpus2q2ipgstidmrs8zmhnv3rt7rknhln6d2ffirkvezvieexgehgi/ptnyngqjzlygkja4+zyixxtdmok/n+ab6wtsskyxereh3ar8kwerwirvx+uofveh3dgmdw1347syjbl/ilgkx5xkozcbfb1f0=,lzkg22zbnsuohagauapebn541x5ohuk7rlvnhshwdm/ba4dcip1f/3bnu4gaelqu6cds/0fg9li5csphe8pyhr1ii/tncuyxqhmf9bhyd6ugwoftfvlmtp6rdopvrpg24rsjjbwy2kuoojjk5uv6futmbrstvobezaxykzmm2m4=,r4qed2psvrtr8tkbtjnnfubw+yr4di+gtogjwyer7qzk9hlduvllzuseepwjtbpz+uurvmplin5wm9ge29ft5as4okddplih8kwnis9y3r9tgh3mnsutgrgayanniy9ji5wnziz9ce2cfzlxoyuzxocsvfoxuw70ty0uklvm/78=";
var xhr = new xmlhttprequest();
xhr.open('get', 'http://127.0.0.1:8080/demo3/sayhello');
xhr.setrequestheader("x-access-token",token);
xhr.send(null);
xhr.onload = function(e) {
    var xhr = e.target;
    console.log(xhr.responsetext);
}

输出结果

ƒ (e) {
    var xhr = e.target;
    console.log(xhr.responsetext);
}
vm433:8 hello world --- 3

说明跨域成功,换个网址如测试依旧出现需要跨域的错误提示,证明该配置正确,该方案测试通过。

2.3 拦截器实现

通过实现fiter接口在请求中添加一些header来解决跨域的问题

@component
public class corsfilter implements filter {

    @override
    public void dofilter(servletrequest request, servletresponse response, filterchain chain)
            throws ioexception, servletexception {
        httpservletresponse res = (httpservletresponse) response;
        res.addheader("access-control-allow-credentials", "true");
        res.addheader("access-control-allow-origin", "*");
        res.addheader("access-control-allow-methods", "get, post, delete, put");
        res.addheader("access-control-allow-headers", "content-type,x-caf-authorization-token,sessiontoken,x-token");
        if (((httpservletrequest) request).getmethod().equals("options")) {
            response.getwriter().println("ok");
            return;
        }
        chain.dofilter(request, response);
    }
    @override
    public void destroy() {
    }
    @override
    public void init(filterconfig filterconfig) throws servletexception {
    }
}

三、更多

3.1 源码地址

github 示例代码