解决跨域问题

前言

跨域问题,是web开发绕不开的难题首先要认识这几点

1.跨域是只存在与浏览器端,不存在与其他环境如:安卓/iso/js/java等其他环境.
2.跨域请求能发出去,服务端能收到请求并正常的返回结果,只是结果被浏览器拦截了.

之所以会跨域是,因为受到了同源策略的限制,同源政策是一种约定,是浏览器的核心也是最基本的安全功能
同源的内容有: 域名 , 协议 , 端口

浏览器出于安全的考虑,使用 XMLHttpRequest对象发起 HTTP请求时必须遵守同源策略,否则就是跨域的HTTP请求,默认情况下是被禁止的。换句话说,浏览器安全的基石是同源策略。

浏览器出于安全的考虑,使用 XMLHttpRequest对象发起 HTTP请求时必须遵守同源策略,否则就是跨域的HTTP请求,默认情况下是被禁止的。换句话说,浏览器安全的基石是同源策略。


什么是CROS?

CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing),允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。它通过服务器增加一个特殊的Header[Access-Control-Allow-Origin]来告诉客户端跨域的限制,如果浏览器支持CORS、并且判断Origin通过的话,就会允许XMLHttpRequest发起跨域请求。

CORS Header
  • Access-Control-Allow-Origin: http://localhost:8080
  • Access-Control-Max-Age:86400
  • Access-Control-Allow-Methods:GET, POST, OPTIONS, PUT, DELETE
  • Access-Control-Allow-Headers: content-type
  • Access-Control-Allow-Credentials: true

含义解释:
1、Access-Control-Allow-Origin 允许http://localhost:8080域(自行设置,这里只做示例)发起跨域请求
2、Access-Control-Max-Age 设置在86400秒不需要再发送预校验请求
3、Access-Control-Allow-Methods 设置允许跨域请求的方法
4、Access-Control-Allow-Headers 允许跨域请求包含content-type
5、Access-Control-Allow-Credentials 设置允许Cookie


filtr(过滤器) 方式解决跨域

在项目中添加Filter类:

package com.zx.filter;

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

public class AllowOriginFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO 其他处理
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//        强转为httpRequest
        HttpServletRequest request = (HttpServletRequest) servletRequest;
//        强转为httpResponse
        HttpServletResponse response = (HttpServletResponse) servletResponse;

//        获取请求头中的 Origin:起源
        String origin = request.getHeader("Origin");

        if (origin != null && origin != "") {
            //设置响应头,允许跨域访问
            //带cookie请求时,必须为全匹配,不能使用*
            /**
             * 表示允许 origin 发起跨域请求。
             */
            response.addHeader("Access-Control-Allow-Origin", origin);

            /**
             * GET,POST,OPTIONS,PUT,DELETE 表示允许跨域请求的方法
             */
            response.addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, DELETE");

            /**
             * 表示在86400秒内不需要再发送预校验请求
             */
            response.addHeader("Access-Control-Max-Age", "86400");

            //支持所有自定义头
            String headers = request.getHeader("Access-Control-Request-Headers");

            if (headers != null && headers != "") {
                //允许JSON请求,并进行预检命令缓存
                response.addHeader("Access-Control-Allow-Headers", headers);
            }

            response.addHeader("Access-Control-Max-Age", "3600");

            //允许cookie
            response.addHeader("Access-Control-Allow-Credentials", "true");
            filterChain.doFilter(servletRequest, response);
        }

    }

    @Override
    public void destroy() {
        // TODO 其他处理
    }
}

Springboot中解决跨域

两种方法解决跨域问题

在SpringBoot项目中,推崇的都是约定优先于配置,尽量少使用配置

一. 注入重写方法 (WebMvcConfigurer)

在解决跨越的问题上,只需要进行一个对象,对其进行重写方法即可

整个Application的handler允许跨域

package com.zx.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CORSConfig {
    
    @Bean
    public WebMvcConfigurer corsConfigurer(){
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry){
                registry.addMapping("/**") // 添加映射
                        .allowedHeaders("*")  //允许的标头
                        .allowedMethods("*")  //允许的方法
                        .allowedOrigins("*"); //允许的起源
            }
        };
    }
}

二. @CrossOrigin

介绍:

只需要在允许跨域的接口方法上进行添加注解即可,也可以直接在Controller类上添加,表示该Controller所有方法均允许跨域访问。

1. @CrossOrigin写在方法上

您可以添加到@RequestMapping . unk处理方法一个@ crosssource注释,以便在它上启用CORS(默认的@CrossOrigin允许@RequestMapping注释中指定的所有起源和HTTP方法):

package com.zx.controller;

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/admin")
public class AdminController {

    @CrossOrigin
    @GetMapping("/test")
    public void test(){
        System.out.println("你好");
    }
}
2.@CrossOrigin写在类上

为整个控制器启用CORS:

package com.zx.controller;

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/admin")
@CrossOrigin(origins = "http://localhost:80",maxAge = 3600)
public class AdminController {
    
    @GetMapping("/test")
    public void test(){
        System.out.println("你好");
    }
}

Nginx 中跨域解决

Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。

其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、简单的配置文件和低系统资源的消耗而闻名。

反向代理

反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。

要求

确认服务器端是没有处理跨域

跨域主要涉及的四个响应头
  1. Access-Control-Allow-Origin

用于设置允许跨域请求源地址(预检请求和正式请求在跨域时候都会验证)

  1. Access-Control-Allow-Headers

跨域允许携带的特殊信息字段(只在预检请求验证)

  1. Access-Control-Allow-Methods

跨域允许的请求方式或者说HTTP动词(只是预检请求验证)

  1. Access-Control-Allow-Credentials

是否允许跨域使用cookies,如果要跨域使用cookies,可以添加上此请求响应头,值设为true(设置或者不设置,都不会影响请求发送,只会影响在跨域时候是否要携带cookies,但是如果设置,预检请求和正式请求都需要设置)。不过不建议跨域使用(项目中用到过,不过不稳定,有些浏览器带不过去),除非必要,因为有很多方案可以代替。

nginx配置文件
upstream zx.com {
        # weight 分量 代表分给该端口的分量
        server localhost:8081 weight=1;
        server localhost:8082 weight=2;
        server localhost:8083 weight=3;
        server localhost:8084 weight=4;
        # backup 后备 后备隐藏能源
        server localhost:8085 backup;
        server localhost:8086 backup;
    }

    server {
        listen       8088;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            # 解决跨域问题
            add_header Access-Control-Allow-Origin *;
            add_header Access-Control-Allow-Headers X-Requested-With;
            add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
            proxy_pass http://zx.com;
        }

        # * location / {
        #     root   html;
        #     index  index.html index.htm;
        # }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }
nginx的cmd命令
  1. 启动服务: start nginx
  2. 退出服务: nginx -s quit
  3. 强制关闭服务: nginx -s stop
  4. 重载服务: nginx -s reload (重载服务配置文件,类似重启,服务不会终止)
  5. 验证配置文件: nginx -t
  6. 使用配置文件: nginx -c “配置文件路径”
  7. 使用帮助: nginx -h
    注: 可以通过DOS命令服务:也可以直接双击nginx.exe启动服务;