激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Spring實現處理跨域請求代碼詳解

Spring實現處理跨域請求代碼詳解

2021-03-02 10:39滄海一滴 Java教程

這篇文章主要介紹了Spring實現處理跨域請求代碼詳解,具有一定借鑒價值,需要的朋友可以了解下。

一次正常的請求

最近別人需要調用我們系統的某一個功能,對方希望提供一個api讓其能夠更新數據。由于該同學是客戶端開發,于是有了類似以下代碼。

?
1
2
3
4
5
6
7
8
@RequestMapping(method = RequestMethod.POST, value = "/update.json", produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody Contacter update(@RequestBody Contacter contacterRO) {
    logger.debug("get update request {}", contacterRO.toString());
    if (contacterRO.getUserId() == 123) {
        contacterRO.setUserName("adminUpdate-wangdachui");
    }
    return contacterRO;
}

客戶端通過代碼發起http請求來調用。接著,該同學又提出:希望通過瀏覽器使用js調用,于是便有跨域問題。

為何跨域

簡單的說即為瀏覽器限制訪問A站點下的js代碼對B站點下的url進行ajax請求。假如當前域名是www.abc.com,那么在當前環境中運行的js代碼,出于安全考慮,正常情況下不能訪問www.zzz.com域名下的資源。

例如:以下代碼再本域名下可以通過js代碼正常調用接口

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(function() {
    var url = "http://localhost:8080/api/Home/update.json";
    var data = {
        "userId": 123,
        "userName": "wangdachui"
      };
    $.ajax({
        url: url,
            type: 'POST',
            dataType: 'json',
            data: $.toJSON(data),
            contentType: 'application/json'
    }
    ).done(function(result) {
        console.log("success");
        console.log(result);
    }
    ).fail(function() {
        console.log("error");
    }
    )
}
)()

輸出為:

?
1
Object {userId: 123, userName: "adminUpdate-wangdachui"}

但是在其他域名下訪問則出錯:

?
1
2
OPTIONS http://localhost:8080/api/Home/update.json
XMLHttpRequest cannot load http://localhost:8080/api/Home/update.json. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 403.

解決方案

JSONP

使用jsonp來進行跨域是一種比較常見的方式,但是在接口已經寫好的情況下,無論是服務端還是調用端都需要進行改造且要兼容原來的接口,工作量偏大,于是我們考慮其他方法。

CORS協議

按照參考資料的說法:每一個頁面需要返回一個名為‘Access-Control-Allow-Origin'的HTTP頭來允許外域的站點訪問。你可以僅僅暴露有限的資源和有限的外域站點訪問。在COR模式中,訪問控制的職責可以放到頁面開發者的手中,而不是服務器管理員。當然頁面開發者需要寫專門的處理代碼來允許被外域訪問。 我們可以理解為:如果一個請求需要允許跨域訪問,則需要在http頭中設置Access-Control-Allow-Origin來決定需要允許哪些站點來訪問。如假設需要允許www.foo.com這個站點的請求跨域,則可以設置:Access-Control-Allow-Origin:http://www.foo.com。或者Access-Control-Allow-Origin: * 。 CORS作為HTML5的一部分,在大部分現代瀏覽器中有所支持。

CORS具有以下常見的header

?
1
2
3
4
5
6
7
8
Access-Control-Allow-Origin: http://foo.org
Access-Control-Max-Age: 3628800
Access-Control-Allow-Methods: GET,PUT, DELETE
Access-Control-Allow-Headers: content-type
"Access-Control-Allow-Origin"表明它允許"http://foo.org"發起跨域請求
"Access-Control-Max-Age"表明在3628800秒內,不需要再發送預檢驗請求,可以緩存該結果
"Access-Control-Allow-Methods"表明它允許GET、PUT、DELETE的外域請求
"Access-Control-Allow-Headers"表明它允許跨域請求包含content-type頭

CORS基本流程

首先發出預檢驗(Preflight)請求,它先向資源服務器發出一個OPTIONS方法、包含“Origin”頭的請求。該回復可以控制COR請求的方法,HTTP頭以及驗證等信息。只有該請求獲得允許以后,才會發起真實的外域請求。

Spring MVC支持CORS

?
1
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 403.

從以上這段錯誤信息中我們可以看到,直接原因是因為請求頭中沒有Access-Control-Allow-Origin這個頭。于是我們直接想法便是在請求頭中加上這個header。服務器能夠返回403,表明服務器確實對請求進行了處理。

MVC 攔截器

首先我們配置一個攔截器來攔截請求,將請求的頭信息打日志。

?
1
2
3
4
5
6
7
8
9
10
11
12
DEBUG requestURL:/api/Home/update.json
DEBUG method:OPTIONS
DEBUG header host:localhost:8080
DEBUG header connection:keep-alive
DEBUG header cache-control:max-age=0
DEBUG header access-control-request-method:POST
DEBUG header origin:null
DEBUG header user-agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36
DEBUG header access-control-request-headers:accept, content-type
DEBUG header accept:*/*
DEBUG header accept-encoding:gzip, deflate, sdch
DEBUG header accept-language:zh-CN,zh;q=0.8,en;q=0.6

在postHandle里打印日志發現,此時response的status為403。跟蹤SpringMVC代碼發現,在org.springframework.web.servlet.DispatcherServlet.doDispatch中會根據根據request來獲取HandlerExecutionChain,SpringMVC在獲取常規的處理器后會檢查是否為跨域請求,如果是則替換原有的實例。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    Object handler = getHandlerInternal(request);
    if (handler == null) {
        handler = getDefaultHandler();
    }
    if (handler == null) {
        return null;
    }
    // Bean name or resolved handler?
    if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = getApplicationContext().getBean(handlerName);
    }
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
    if (CorsUtils.isCorsRequest(request)) {
        CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }
    return executionChain;
}

檢查的方法也很簡單,即檢查請求頭中是否有origin字段

?
1
2
3
public static boolean isCorsRequest(HttpServletRequest request) {
    return (request.getHeader(HttpHeaders.ORIGIN) != null);
}

請求接著會交由 HttpRequestHandlerAdapter.handle來處理,根據handle不同,處理不同的邏輯。前面根據請求頭判斷是一個跨域請求,獲取到的Handler為PreFlightHandler,其實現為:

?
1
2
3
4
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
    corsProcessor.processRequest(this.config, request, response);
}

繼續跟進

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Override
public Boolean processRequest(CorsConfiguration config, HttpServletRequest request, HttpServletResponse response)
        throws IOException {
    if (!CorsUtils.isCorsRequest(request)) {
        return true;
    }
    ServletServerHttpResponse serverResponse = new ServletServerHttpResponse(response);
    ServletServerHttpRequest serverRequest = new ServletServerHttpRequest(request);
    if (WebUtils.isSameOrigin(serverRequest)) {
        logger.debug("Skip CORS processing, request is a same-origin one");
        return true;
    }
    if (responseHasCors(serverResponse)) {
        logger.debug("Skip CORS processing, response already contains \"Access-Control-Allow-Origin\" header");
        return true;
    }
    Boolean preFlightRequest = CorsUtils.isPreFlightRequest(request);
    if (config == null) {
        if (preFlightRequest) {
            rejectRequest(serverResponse);
            return false;
        } else {
            return true;
        }
    }
    return handleInternal(serverRequest, serverResponse, config, preFlightRequest);
}

此方法首先會檢查是否為跨域請求,如果不是則直接返回,接著檢查是否同一個域下,或者response頭里是否具有Access-Control-Allow-Origin字段或者request里是否具有Access-Control-Request-Method。如果滿足判斷條件,則拒絕這個請求。

由此我們知道,可以通過在檢查之前設置response的Access-Control-Allow-Origin頭來通過檢查。我們在攔截器的preHandle的處理。加入如下代碼:

?
1
response.setHeader("Access-Control-Allow-Origin", "*");

此時瀏覽器中OPTIONS請求返回200。但是依然報錯:

?
1
Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.

我們注意到:在request的請求頭里有Access-Control-Request-Headers:accept, content-type,但是這個請求頭的中沒有,此時瀏覽器沒有據需發送請求。嘗試在response中加入:

?
1
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");

執行成功:Object {userId: 123, userName: “adminUpdate-wangdachui”}。

至此:我們通過分析原理使SpringMVC實現跨域,原有實現以及客戶端代碼不需要任何改動。

SpringMVC 4

此外,在參考資料2中,SpringMVC4提供了非常方便的實現跨域的方法。
在requestMapping中使用注解。 @CrossOrigin(origins = “http://localhost:9000”)
全局實現 .定義類繼承WebMvcConfigurerAdapter

?
1
2
3
4
5
6
public class CorsConfigurerAdapter extends WebMvcConfigurerAdapter{
    @Override
        public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/*").allowedOrigins("*");
    }
}

將該類注入到容器中:

?
1
<bean class="com.tmall.wireless.angel.web.config.CorsConfigurerAdapter"></bean>

總結

以上就是本文關于Spring實現處理跨域請求代碼詳解的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續參閱本站其他相關專題。如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!

原文鏈接:https://www.cnblogs.com/softidea/p/6108066.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美黄色一级片视频 | 看免费一级毛片 | 中文字幕国产一区 | xxx18hd18hd日本| 久久区二区 | 成人在线精品视频 | 99久久久精品 | 精品中文字幕视频 | 久久一区二区三区av | 欧美三级一级 | 北原夏美av| 亚洲免费片 | 欧美中文字幕一区二区三区亚洲 | 麻豆视频免费网站 | 91精品国产99久久久久久 | 国产乱淫av| 精品久久久久久久久中文字幕 | 美女黄色影院 | 啪啪毛片 | 国产成人精品一区二区视频免费 | 日韩精品免费一区二区三区 | 亚洲国产精品一区二区三区 | 久久久精品综合 | 嗯哈~不行好大h双性 | 蜜桃精品视频 | 国产精品视频一区二区三区综合 | 一区二区三区四区高清视频 | 欧美日韩免费在线观看视频 | 黄网站免费在线看 | 日本精品视频一区二区三区四区 | h色网站免费观看 | 久久国产精品二区 | 伊人yinren22综合网色 | 国产午夜精品在线 | 日韩视频一区二区三区在线观看 | 国产91在线高潮白浆在线观看 | 国产一级毛片不卡 | 久综合色 | 日本aⅴ在线 | 亚洲99影视一区二区三区 | 自拍亚洲伦理 |