天天看點

如何解決跨域問題

1.什麼是跨域?

當一個頁面請求url的協定、域名、端口三者之間任何一者與目前頁面url不同即為跨域。舉個例子:

如何解決跨域問題

2.為什麼會出現跨域問題

出現跨域問題是源于浏覽器的同源政策限制的。同源政策(Same origin policy)是一種約定,它是浏覽器針對安全功能的一種實作,如果缺少了同源政策,浏覽器很容易受到XSS,CSFR等網絡攻擊。

3.跨域會導緻什麼問題

  • 不能讀取非同源網頁中的 Cookie、LocalStorage 等資料
  • 不能接觸非同源網頁的 DOM 結構
  • 不能向非同源位址發送 AJAX 請求

跨域的現象:

如何解決跨域問題

4.跨域問題的解決方案

4.1 CORS

CORS 跨域資源分享(Cross-Origin Resource Sharing)的辦法是讓每一個頁面需要傳回一個名為Access-Control-Allow-Origin的http頭來允許非同源的站點通路

一般請求隻需在伺服器端設定Access-Control-Allow-Origin,如果是帶cookie的跨域請求那麼前後端都要進行設定

【前端】

①原生ajax

var xhr = new XMLHttpRequest();
// 設定可以攜帶cookie
xhr.withCredentials = true;

xhr.open('post', 'http://water.com/v1', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=gwx');

xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        alert(xhr.responseText);
    }
};
           

② jQuery ajax

$.ajax({
   url: 'http://water.com/v1',
   type: 'get'
  data: {}
  xhrFields: 
      // 設定可以攜帶cookie
      withCredentials: true
  }
})
           

③vue-resource

// 設定可以攜帶cookie
Vue.http.options.credentials = true
           

④ axios

// 設定可以攜帶cookie
axios.defaults.withCredentials = true
           

【後端SpringBoot】

在伺服器響應用戶端的時候,帶上Access-Control-Allow-Origin

① 使用 @CrossOrigin 注解

@RequestMapping("/v1")
@RestController
//@CrossOrigin //不限制指定域名,都可以通路
@CrossOrigin("https://water.com") // 指定域名
public class CorsTestController {
    @GetMapping("/test")
    public String sayHello() {
        return "success";
    }
}
           

② CORS全局配置

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

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

③ 攔截器實作

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

4.2 nginx反向代理

通過修改 nginx.conf 配置檔案做代理轉發

server {
    listen 80;
    server_name www.yamky.com;

 	location ^~/gwx/ {
            proxy_pass http://xxx.com:80;//你要轉發的位址
            proxy_set_header Host $host:$server_port;
            proxy_set_header Remote_Addr $remote_addr;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            client_max_body_size    2048m;
    }
           

4.3 使用網關解決