xhr
先來了解下xhr
xhr,全稱為XMLHttpRequest
,用於與服務器交互數據,是ajax功能實現所依賴的對象,jquery中的ajax就是對 xhr的封裝。
還有axios和fetch請求都屬於xhr請求,都是基於標准 Promise 實現。
ajax cookie跨域處理
簡單說說cookie
和session
的關系
不少朋友搞的不是特別清楚,一知半解的,在這里闡述下
cookie存儲於客戶端瀏覽器,默認生命周期跟隨瀏覽器,瀏覽器關閉,cookie就會失效,tab標簽也關閉了並不會失效
session存儲於服務器,比如tomcat
,默認失效時間30分鍾,當然也可以通過redis來存儲。
這里登錄做個示例說明
未登錄狀態下,匿名用戶通過客戶端瀏覽器請求數據,都是無狀態的(服務端不知道你是誰
)
用戶進行請求登錄操作,登錄成功,服務端會在response header里加一個Set-Cookie
寫入瀏覽器中。
之后客戶端在以后的請求中,會自動在請求頭中攜帶此cookie。
cookie有一些屬性,比如
-
失效時間(跟隨瀏覽器,但是也可以進行持久化。跟localstorage和sessionstorage類似)
-
httponly(設置為true的話,客戶端在控制台就獲取不到)
-
path(默認為/)
同源情況下,比如是前后端不分離的項目,xhr(ajax)請求沒有任何問題,但是會發現,不支持cookie跨域
非同源情況下,xhr(ajax)請求服務端處理了,但是不會進行響應,會顯示如下錯誤。也就是出現了跨域問題。
所以,解決接口跨域和解決xhr cookie跨域,是不一樣的。
解決cookie跨域需要客戶端和服務端都做處理,主要操作在服務端。
客戶端
ajax請求添加該參數即可
xhrFields: {
withCredentials: true
},
同理axios也是如此
axios.defaults.withCredentials = true
注意,修改cookie值直接document修改即可,請求的時候瀏覽器會自動攜帶的。
不需要在header中添加cookie頭,這樣做是沒有任何意義的。比如
headers: {
'Cookie': 'JSESSIONID=6FA9E27092EC212E439851D4831AADE6'
}
服務端
添加允許跨域操作,此處表示Spring
框架,直接用@CrossOrigin
處理即可(最為簡單)
@CrossOrigin(value = "*", allowCredentials = "true")
服務端設置跨域的幾種方式
方式一 重寫addCorsMappings方法
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
.maxAge(3600)
.allowCredentials(true);
}
}
方式二 對單個接口處理
// 需要設置前端請求的url。不支持*
responses.setHeader("Access-Control-Allow-Origin", "http://localhost:63342");
// 設置允許跨域的方法
responses.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
// 之后需要設置允許cookie跨域
response.setHeader("Access-Control-Allow-Credentials", "true");
方式三 @CrossOrigin注解
@CrossOrigin(value = "*", allowCredentials = "true")
方式四 nginx配置添加允許跨域請求
server {
listen 5566;
server_name localhost;
# 指定客戶端的請求地址
add_header 'Access-Control-Allow-Origin' 'http://localhost:63342';
add_header 'Access-Control-Allow-Credentials' true;
add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization,token,r,sign,time";
location / {
if ($request_method = OPTIONS ) {
return 200;
}
proxy_method get;
proxy_set_header X-real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:5005;
proxy_set_header Host $host;
}
}
OK,完美解決!