Vue.js學習(三)—— 分別從前后端Nginx解決SpringBoot+vue.js項目中的跨域問題


一、什么是跨域

  (1)跨域

  由於瀏覽器同源策略,凡是發送請求url的協議、域名、端口三者之間任意一個與當前頁面地址不同即為跨域。存在跨域的情況:

網絡協議不同,如http協議訪問https協議。
端口不同,如80端口訪問8080端口。
域名不同,如qianduanblog.com訪問baidu.com。
子域名不同,如abc.qianduanblog.com訪問def.qianduanblog.com。
域名和域名對應ip,如www.a.com訪問20.205.28.90.

  (2)url格式

  一般格式:協議 + 域名(子域名 + 主域名) + 端口號 + 資源地址

  示例:https://www.dustyblog.cn:8080/say/Hello 是由https + www + dustyblog.cn + 8080 + say/Hello組成。

  只要協議,子域名,主域名,端口號這四項組成部分中有一項不同,就可以認為是不同的域,不同的域之間互相訪問資源,就被稱之為跨域。

  (3)Cors

  CORS全稱為Cross Origin Resource Sharing(跨域資源共享), 每一個頁面需要返回一個名為Access-Control-Allow-Origin的http頭來允許外域的站點訪問,你可以僅僅暴露有限的資源和有限的外域站點訪問。

  我們可以理解為:如果一個請求需要允許跨域訪問,則需要在http頭中設置Access-Control-Allow-Origin來決定需要允許哪些站點來訪問。如假設需要允許https://www.dustyblog.c這個站點的請求跨域,則可以設置:

  Access-Control-Allow-Origin:https://www.dustyblog.cn。

 

二、后端SpringBoot解決

  1、方案一:CORS局部配置-使用@CrossOrigin注解

  (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域上的請求,其他域名不能請求

  (2)在方法上使用@CrossOrigin注解

@RequestMapping("/preUser")
@CrossOrigin("https://blog.csdn.net") 
public Map<String,String> preUser(){
  Map
<String,String> map = new HashMap<String,String>();
  map.put(
"preUser","success");
  return map;
}

  這里指定只有該方法可以處理https://csdn.net域上的請求,其他域名不能請求

  2、方案二:CORS局部配置-手工設置響應頭(局部跨域)

@RequestMapping("/hello")
@ResponseBody
public String index(HttpServletResponse response){
    response.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");
    return "Hello World";
}
Access-Control-Allow-Origin 表示允許哪些原始域進行跨域訪問。
Access-Control-Allow-Credentials表示是否允許客戶端獲取用戶憑據。
Access-Control-Allow-Methods 表示允許哪些跨域請求的提交方式。(例如GET/POST)
Access-Control-Expose-Headers 表示允許暴露哪些頭部信息給客戶端。
Access-Control-Max-Age 表示預檢請求 [Preflight Request] 的最大緩存時間。

  3、方案三:CORS全局配置-實現WebMvcConfigurer(本人習慣用法)

  Spring Boot 2.0中已經廢棄WebMvcConfigurerAdapter類, 開發人員可以通過實現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秒內,不需要再發送預檢驗請求,可以緩存該結果
            }
        };
    }
}

  4、方案四:CORS全局配置-使用Filter方式進行設置(過濾器實現)

  通過實現Fiter接口在請求中添加一些Header來解決跨域的問題,向請求端設置Response Header(響應頭部)的Access-Control-Allow-Origin屬性聲明允許跨域訪問。

@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 {
    }
}

  5、方案五:CORS全局配置-繼承使用Spring Web中的CorsFilter

package com.garyond.hurricane.config;

import org.springframework.stereotype.Component;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import java.util.Arrays;

/**
 *  跨域訪問配置
 *
 *  @author Garyond
 */
@Component
public class CustomCorsFilter extends CorsFilter {

    public CustomCorsFilter() {
        super(configurationSource());
    }

    private static UrlBasedCorsConfigurationSource configurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.setMaxAge(36000L);
        config.setAllowedMethods(Arrays.asList("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/v1/**", config);
        return source;
    }
}

  或者

package com.ranxx.conf;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

/**
 * 跨域問題
 *
 * @author mousejoo
 */
@Configuration
public class CorsConfig {
    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*"); // 1 允許任何域名使用
        corsConfiguration.addAllowedHeader("*"); // 2 允許任何頭
        corsConfiguration.addAllowedMethod("*"); // 3 允許任何方法(post、get等)
        return corsConfiguration;
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig()); // 4
        return new CorsFilter(source);
    }
    

}

  或者

package com.example.longecological.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class GlobalCorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        //1.添加CORS配置信息
        CorsConfiguration config = new CorsConfiguration();
          //放行哪些原始域
          config.addAllowedOrigin("*");
          //是否發送Cookie信息
          config.setAllowCredentials(true);
          //放行哪些原始域(請求方式)
          config.addAllowedMethod("*");
          //放行哪些原始域(頭部信息)
          config.addAllowedHeader("*");
          //暴露哪些頭部信息(因為跨域訪問默認不能獲取全部頭部信息)
          config.addExposedHeader("content-type");

        //2.添加映射路徑
        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration("/**", config);

        //3.返回新的CorsFilter.
        return new CorsFilter(configSource);
    }
}

  

三、前端Vue.js解決

  解決方案:采用proxyTable配置代理跨域

  (1)打開項目根目錄下的config/index.js文件,參考以下proxyTable部分的配置:

module.exports = {
  dev: {
    // Paths
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    // *********代理跨域 主要代碼**********
    proxyTable: {
      '/api': {  //匹配接口路徑中的 /api,可以隨意命名
        target: 'http://********:9001/api', //目標接口地址,設置調用的接口域名和端口號 別忘了加http、https
        changeOrigin: true, //是否跨域
        secure: true, // 允許https請求,https必須添加這個設置
        pathRewrite: {
          '^/api': '' // 路徑重寫 將 target 中的目標接口地址重寫為 /api,這里理解成用‘/api’代替target里面的地址,后面組件中我們掉接口時直接用api代替 比如我要調用'http://40.00.100.100:3002/user/add',直接寫‘/api/user/add’即可
  } } }, }

  注意:每次修改配置文件需要重啟服務才能生效:npm run dev

  (2)通過axios來實現發送訪問

  在main.js中導入已安裝好的axios,並掛載到原型上

import Axios from 'axios'  //導入axios

//將axios掛載到原型上
Vue.prototype.$axios = Axios;

  (3)通過this.$axios.get().then()來實現數據請求

//發送get請求
show() {
      //用/api來代理'http://localhost:8083'
      this.$axios
        .get("/api/selectall")
        .then(res => {
          this.list = res.data.result;
          // }
        })
        .catch(e => {
          console.log(e);
        });
        },

//發送post請求
add() {
      this.$axios({
        method: "post",
        url: "/api/saveinfo",
        params: {
          name: this.name //傳遞的參數
        }
      }).then(res => {
                this.show();
      });
    },

  注意:此種跨域解決方案,只能適用於測試階段,因為項目打包發布之后,由於proxyTable不能再使用,所以無法跨域了。正式環境中,前端項目和后端項目放在一起就不存在跨域問題了。如果非要跨域,則可以采取上面的后端解決方法或者下面的Nginx替代前端的proxyTable代理功能。

 

三、Nginx解決生產環境跨域問題

  1、安裝好Nginx之后,打開安裝目錄下的conf/nginx.conf文件,參考以下server的簡單配置:

server {
        listen       9091;       #監聽的端口
        server_name  localhost;  #服務器名稱

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   E:\hld-work\university\dist;  #項目物理路徑
            index  index.html index.htm;         #項目的默認首頁
        }   
        
        location /api {                                #檢測並替換接口內的字符串
            proxy_pass http://**********:9001/api;   #跨域訪問的目標URL
            proxy_set_header Host $host; 
            proxy_set_header X-Real-IP $remote_addr; 
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
            client_max_body_size 100m; 
        }
    }

  注:每次修改配置文件需要重啟服務才能生效

  2、Nginx常用相關命令:

  需要在Nginx文件目錄下運行命令行工具

  (1)啟動

start nginx 或 nginx.exe

  (2)停止

nginx.exe -s stop 或 ginx.exe -s quit

  注:stop是快速停止nginx,可能並不保存相關信息;quit是完整有序的停止nginx,並保存相關信息。

  (3)重新載入

nginx.exe -s reload

  (4)重新打開日志文件

nginx.exe -s reopen

  (5)查看版本

nginx -v

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM