生活随笔
收集整理的這篇文章主要介紹了
精选文章 什么是跨域?怎么解决跨域问题?
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、什么是跨域
跨域,指的是瀏覽器不能執行其他網站的腳本。它是由瀏覽器的同源策略造成的,是瀏覽器對JavaScript施加的安全限制。
所謂同源是指,域名,協議,端口均相同,不明白沒關系,舉個栗子:
http://www.123.com/index.html 調用 http://www.123.com/server.PHP (非跨域)
http://www.123.com/index.html 調用 http://www.456.com/server.php (主域名不同:123/456,跨域)
http://abc.123.com/index.html 調用 http://def.123.com/server.php (子域名不同:abc/def,跨域)
http://www.123.com:8080/index.html 調用 http://www.123.com:8081/server.php (端口不同:8080/8081,跨域)
http://www.123.com/index.html 調用 https://www.123.com/server.php(協議不同:http/https,跨域)
請注意:localhost和127.0.0.1雖然都指向本機,但也屬于跨域。
瀏覽器執行javascript腳本時,會檢查這個腳本屬于哪個頁面,如果不是同源頁面,就不會被執行。
Cookie、LocalStorage、IndexedDB 等存儲性內容 DOM 節點 AJAX 請求不能發送
二、前端的解決辦法
JSONP:
使用方式就不贅述了,但是要注意JSONP只支持GET請求,不支持POST請求。
JSONP原理
ajax請求受同源策略影響,不允許進行跨域請求,而script標簽src屬性中的鏈接卻可以訪問跨域的js腳本,利用這個特性,服務端不再返回JSON格式的數據,而是返回一段調用某個函數的js代碼,在src中進行了調用,這樣實現了跨域。
jsonp其實是一種特定的格式,一般是 fun(json格式參數),
服務端:
header ( 'Content-type: application/json' ) ; $jsoncallback
= htmlspecialchars ( $_REQUEST
[ 'jsoncallback' ] ) ;
$json_data
= '["customername1","customername2"]' ;
echo $jsoncallback
. "(" . $json_data
. ")" ;
客戶端:
function callbackFunction(result, methodName)
{console.log(result[0]);
};
其實就是返回一個js文件,里面執行了callbackFunction方法;因為引用js文件不存在跨域的問題,這樣問題就解決啦~~~
代理(Nginx或者Vue-Cli)
例如www.123.com/index.html需要調用www.456.com/server.php,可以寫一個接口www.123.com/server.php,由這個接口在后端去調用www.456.com/server.php并拿到返回值,然后再返回給index.html,這就是一個代理的模式。相當于繞過了瀏覽器端,自然就不存在跨域問題。比如vue-cli中開啟代理服務器的方式。
devServer
: { proxy
: { '/atguigu' : { target
: 'http://localhost:5000' , pathRewrite
: { '^/atguigu' : '' } , } , '/demo' : { target
: 'http://localhost:5001' , pathRewrite
: { '^/demo' : '' } , } }
nginx反向代理 實現原理類似于Node中間件代理,需要你搭建一個中轉nginx服務器,用于轉發請求。使用nginx反向代理實現跨域,是最簡單的跨域方式。只需要修改nginx的配置即可解決跨域問題,支持所有瀏覽器,支持session,不需要修改任何代碼,并且不會影響服務器性能。實現思路:通過nginx配置一個代理服務器做跳板機,反向代理訪問domain2接口,并且可以順便修改cookie中domain信息,方便當前域cookie寫入,實現跨域登錄。將nginx目錄下的nginx.conf修改如下:
server
{ listen
81 ; server_name www
. domain1
. com
; location
/ { proxy_pass http
: proxy_cookie_domain www
. domain2
. com www
. domain1
. com
; #修改cookie里域名index index
. html index
. htm
; # 當用webpack
- dev
- server等中間件代理接口訪問nignx時,此時無瀏覽器參與,故沒有同源限制,下面的跨域配置可不啟用add_header Access
- Control
- Allow
- Origin http
: add_header Access
- Control
- Allow
- Credentials true
; add_header Access
- Control
- Allow
- Methods GET
, POST
, OPTIONS
; add_header Access
- Control
- Allow
- Headers
* ; }
}
這樣我們的前端代理只要訪問 http:www.domain1.com:81/*就可以了。
修改header(XHR2方式)
header(‘Access-Control-Allow-Origin:*’);//允許所有來源訪問 header(‘Access-Control-Allow-Method:POST,GET’);//允許訪問的方式
三、后端的解決方式
CORS(Cross-origin resource sharing),跨域資源共享。CORS 其實是瀏覽器制定的一個規范,瀏覽器會自動進行 CORS 通信,它的實現則主要在服務端,它通過一些 HTTP Header 來限制可以訪問的域,例如頁面 A 需要訪問 B 服務器上的數據,如果 B 服務器 上聲明了允許 A 的域名訪問,那么從 A 到 B 的跨域請求就可以完成。對于那些會對服務器數據產生副作用的 HTTP 請求,瀏覽器會使用 OPTIONS 方法發起一個預檢請求(preflight request),從而可以獲知服務器端是否允許該跨域請求,服務器端確認允許后,才會發起實際的請求。在預檢請求的返回中,服務器端也可以告知客 戶端是否需要身份認證信息。我們只需要設置響應頭,即可進行跨域請求。
雖然設置 CORS 和前端沒什么關系,但是通過這種方式解決跨域問題的話,會在發送請求時出現兩種情況,分別為簡單請求和復雜請求。
只要同時滿足以下兩大條件,就屬于簡單請求:
使用GET、HEAD、POST方法之一; Content-Type的值僅限于:text/plain、multipart/form-data、application/x-www-form-urlencoded,請求中的任意 XMLHttpRequestUpload 對象均沒有注冊任何事件監聽器; XMLHttpRequestUpload 對象可以使用 XMLHttpRequest.upload 屬性訪問;
不符合以上條件的請求就肯定是復雜請求了。 復雜請求的CORS請求,會在正式通信之前,增加一次HTTP查詢請求,稱為"預檢"請求,該請求是 option 方法的,通過該請求來知道服務端是否允許跨域請求。我們用PUT向后臺請求時,屬于復雜請求,后臺需被請求的Servlet中添加Header設置,Access-Control-Allow-Origin這個Header在W3C標準里用來檢查該跨域請求是否可以被通過,如果值為*則表明當前頁面可以跨域訪問。默認的情況下是不允許的。
配置過濾器的方式:
@WebFilter ( filterName
= "corsFilter" , urlPatterns
= "/*" , initParams
= { @WebInitParam ( name
= "allowOrigin" , value
= "*" ) , @WebInitParam ( name
= "allowMethods" , value
= "GET,POST,PUT,DELETE,OPTIONS" ) , @WebInitParam ( name
= "allowCredentials" , value
= "true" ) , @WebInitParam ( name
= "allowHeaders" , value
= "Content-Type,X-Token" ) } )
public class CorsFilter implements Filter { private String allowOrigin
; private String allowMethods
; private String allowCredentials
; private String allowHeaders
; private String exposeHeaders
; @Override public void init ( FilterConfig filterConfig
) { allowOrigin
= filterConfig
. getInitParameter ( "allowOrigin" ) ; allowMethods
= filterConfig
. getInitParameter ( "allowMethods" ) ; allowCredentials
= filterConfig
. getInitParameter ( "allowCredentials" ) ; allowHeaders
= filterConfig
. getInitParameter ( "allowHeaders" ) ; exposeHeaders
= filterConfig
. getInitParameter ( "exposeHeaders" ) ; } @Override public void doFilter ( ServletRequest servletRequest
, ServletResponse servletResponse
, FilterChain filterChain
) throws IOException , ServletException { HttpServletRequest request
= ( HttpServletRequest ) servletRequest
; HttpServletResponse response
= ( HttpServletResponse ) servletResponse
; if ( ! StringUtils . isEmpty ( allowOrigin
) ) { if ( allowOrigin
. equals ( "*" ) ) { response
. setHeader ( "Access-Control-Allow-Origin" , allowOrigin
) ; } else { List < String > allowOriginList
= Arrays . asList ( allowOrigin
. split ( "," ) ) ; if ( allowOriginList
. size ( ) > 0 ) { String currentOrigin
= request
. getHeader ( "Origin" ) ; if ( allowOriginList
. contains ( currentOrigin
) ) { response
. setHeader ( "Access-Control-Allow-Origin" , currentOrigin
) ; } } } } if ( ! StringUtils . isEmpty ( allowMethods
) ) { response
. setHeader ( "Access-Control-Allow-Methods" , allowMethods
) ; } if ( ! StringUtils . isEmpty ( allowCredentials
) ) { response
. setHeader ( "Access-Control-Allow-Credentials" , allowCredentials
) ; } if ( ! StringUtils . isEmpty ( allowHeaders
) ) { response
. setHeader ( "Access-Control-Allow-Headers" , allowHeaders
) ; } if ( ! StringUtils . isEmpty ( exposeHeaders
) ) { response
. setHeader ( "Access-Control-Expose-Headers" , exposeHeaders
) ; } filterChain
. doFilter ( servletRequest
, servletResponse
) ; } @Override public void destroy ( ) { }
}
基于SpringBoot: 以下代碼配置也可以完美解決前后端跨域請求問題
@Configuration
public class CorsConfig { @Bean public CorsFilter corsFilter ( ) { final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource
= new UrlBasedCorsConfigurationSource ( ) ; final CorsConfiguration corsConfiguration
= new CorsConfiguration ( ) ; corsConfiguration
. setAllowCredentials ( true ) ; corsConfiguration
. addAllowedOrigin ( "*" ) ;
corsConfiguration
. addAllowedHeader ( "*" ) ; corsConfiguration
. addAllowedMethod ( "*" ) ; corsConfiguration
. setMaxAge ( 300L ) ; urlBasedCorsConfigurationSource
. registerCorsConfiguration ( "/**" , corsConfiguration
) ; return new CorsFilter ( urlBasedCorsConfigurationSource
) ; }
}
SpringBoot@CrossOrigin注解
這個方法僅對Java有用。springboot中,在Controller類上添加一個 @CrossOrigin(origins ="*") 注解就可以實現對當前controller 的跨域訪問了,當然這個標簽也可以加到方法上,或者直接加到入口類上對所有接口進行跨域處理,注意這個注解只在JDK1.8版本以上才起作用。
使用SpringCloud網關
服務網關(zuul)又稱路由中心,用來統一訪問所有api接口,維護服務。Spring Cloud Zuul通過與Spring Cloud Eureka的整合,實現了對服務實例的自動化維護,所以在使用服務路由配置的時候,我們不需要向傳統路由配置方式那樣去指定具體的服務實例地址,只需要通過Ant模式配置文件參數即可。當然SpringCloud網關和微服務調用中心不只有這一種組合。
四、總結
CORS支持所有類型的HTTP請求,是跨域HTTP請求的根本解決方案 JSONP只支持GET請求,JSONP的優勢在于支持老式瀏覽器,以及可以向不支持CORS的網站請求數據。 不管是Node中間件代理還是nginx反向代理,主要是通過同源策略對服務器不加限制。
日常工作中,用得比較多的跨域方案是cors和nginx反向代理
參考文章
與50位技術專家面對面 20年技術見證,附贈技術全景圖
總結
以上是生活随笔 為你收集整理的精选文章 什么是跨域?怎么解决跨域问题? 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。