摘要:這個過程是瀏覽器會發一次請求,詢問服務器是否允許代碼如下完了以后,客戶端就可以順利請求服務器接口了。
此文講解在RESTful API中跨域問題在項目中如何處理的!
CORS 是 Cross Origin Resource Sharing 的縮寫, 定義了瀏覽器和服務器間共享內容的新方式,通過它瀏覽器和服務器可以安全地進行跨域訪問,它是 JSONP 的現代繼任 者。服務器上的 CORS 配置可以精細地指定允許跨域訪問的條件:來源域、HTTP 方法、請求頭、內容類型等等。并 且,CORS 讓 XMLHttpRequest 也可以跨域,我們可以像往常一樣編寫 AJAX 調用代碼。所有現代瀏覽器都支持 CORS,所以你應該可以放心地使用它,只有在需要兼容老舊瀏覽器的場合,才用 JSONP做fallback。支持 CORS 的瀏覽器在嘗試進行跨域 XMLHttpRequest 時,會先發出一個“事前檢查”,就是一個OPTIONS 請求,其中會包括一些有用的請求頭:
Access-Controll-Request-Headers: accept, content-type Access-Controll-Request-Method: POST
接著服務器會做出響應:
Access-Control-Allow-Origin: * Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-Requested-With, Content-Type, Accept Access-Control-Max-Age: 1728000
最后瀏覽器會根據服務器的響應頭,判斷請求是否在服務器規定的范圍內。比如來源是否在 Access-Control-Allow- Origin 里,HTTP 方法是不是在 Access-Control-Allow-Methods 里面,有沒有不在 Allow-Headers 里面的請求頭。如果以上條件都符合,那么瀏覽器就會放行這次請求,并且在Access-Control-Max-Age 指定的時間內(單位是秒,以上設置的是 20 天)不需要再進行這種“事前檢查”。
在以上服務器響應頭中,Access-Control-Allow-Headers 不可以使用通配符。所以如果你要允許所有請求頭,不妨把瀏覽器發來的 Access-Control-Request-Header 直接返回。
事實上,如果跨域請求是“簡單請求”,也就是 HTTP 方法為 GET、HEAD、POST,請求體的 MIME Type 是以下其中一種:application/x-www-form-urlencoded、multipart/form-data 或者text/plain,并且沒有自定義的請求頭。這時瀏覽器只根據請求頭中的 Origin 和服務器返回的Access-Control-Allow-Origin 就可以判斷了。但我們是 RESTful API,請求體是application/json,所以只能用上面那種“事前檢查”的方式。另外,利用 CORS 還可以在跨域請求中發送 Cookie,這個特性是很有用的。只需要為 XMLHttpRequest 對象設置 withCredentials 屬性:
var xhr = new XMLHttpRequest(); xhr.withCredentials = true; java在resteasy中設置 response.getOutputHeaders().putSingle("Access-Control-Allow-Credentials",true);
但這種情況下,就不能指定 Access-Control-Allow-Origin: *,而是必須指定一個來源,比如http://mydomain.com。
java 操作:resteasy 設置如下
先提供options請求,告訴客戶端允許客戶端可以帶什么樣的頭信息過來。比如:
客戶要封裝一個復雜json數據來請求服務器,這時服務器需要需要允許客戶端頭信息中的content-type 為application/json。這個過程是瀏覽器會發一次options請求,詢問v服務器是否允許
代碼如下:
@OPTIONS @Path(value = "creatorunion/works") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Response uploadWorks(@Context HttpRequest request, @Context HttpResponse response) { HttpHeaders header = request.getHttpHeaders(); ListrequestHeader = header.getRequestHeader("Origin"); if(CollectionUtils.isNotEmpty(requestHeader)){ String host = requestHeader.get(0); response.getOutputHeaders().putSingle("Access-Control-Allow-Origin",host); } response.getOutputHeaders().putSingle("Access-Control-Allow-Headers","X-Requested-With, accept, origin, content-type"); response.getOutputHeaders().putSingle("Content-Type","application/json;charset=utf-8"); response.getOutputHeaders().putSingle("Access-Control-Allow-Credentials",true); response.getOutputHeaders().putSingle("Access-Control-Allow-Methods","GET,POST,PUT,DELETE,OPTIONS"); return Response.status(200).entity("").build(); }
完了以后,客戶端就可以順利請求服務器(接口:creatorunion/works)了。
但這樣寫有個問題,每個接口都需要去設置,由于在項目中使用了netty作為容器需要在netty容器里添加自定義handlers來統一處理resteasy &netty的淵源請參考:
http://docs.jboss.org/resteasy/docs/3.0.17.Final/userguide/html_single/index.html#d4e1485
代碼如下:
private void start(ResteasyDeployment deployment,SecurityDomain domain) throws Exception { _netty = new MyNettyJaxrsServer(); _netty.setDeployment(deployment); _netty.setPort(_port); _netty.setRootResourcePath(_serverIP); _netty.setSecurityDomain(domain); //添加自定義handler ListcustomHandlers = Lists.newArrayList(new CorsHeadersChannelHandler(),new OPTIONHandler()) ; _netty.setCustomHandlers(customHandlers); _netty.start(); }
第一個
Handler :OPTIONHandler @Sharable public class OPTIONHandler extends SimpleChannelInboundHandler{ @Override protected void channelRead0(ChannelHandlerContext ctx, NettyHttpRequest request) throws Exception { if("OPTIONS".equals(request.getHttpMethod().toUpperCase())){ NettyHttpResponse response = request.getResponse(); response.reset(); response.setStatus(200); List requestHeader = request.getMutableHeaders().get("Origin"); String host = ""; if(requestHeader!=null && !requestHeader.isEmpty()){ host = requestHeader.get(0); } response.getOutputHeaders().add("Access-Control-Allow-Origin", host); response.getOutputHeaders().add("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS"); response.getOutputHeaders().putSingle("Access-Control-Allow-Credentials",true);//允許帶cookie訪問 response.getOutputHeaders().add("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Content-Length"); if (!request.getAsyncContext().isSuspended()) { response.finish(); } } ctx.fireChannelRead(request); } }
第二個
Handler :CorsHeadersChannelHandler @Sharable public class CorsHeadersChannelHandler extends SimpleChannelInboundHandlernodejs操作:{ @Override protected void channelRead0(ChannelHandlerContext ctx, NettyHttpRequest request) throws Exception { List requestHeader = request.getMutableHeaders().get("Origin"); String host = ""; if(requestHeader!=null && !requestHeader.isEmpty()){ host = requestHeader.get(0); } request.getResponse().getOutputHeaders().add("Access-Control-Allow-Origin", host); request.getResponse().getOutputHeaders().add("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS"); request.getResponse().getOutputHeaders().add("Access-Control-Allow-Credentials",true);//允許帶cookie訪問 request.getResponse().getOutputHeaders().add("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Content-Length"); ctx.fireChannelRead(request); } }
對于nodejs做如下配置可允許資源的跨域訪問:
設置CORS跨域訪問
app.all("*", function (req, res, next) { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "X-Requested-With, accept, origin, content-type"); res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS"); res.header("X-Powered-By", " 3.2.1") res.header("Content-Type", "application/json;charset=utf-8"); next(); });
補充:
參考https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66026.html
摘要:但是這種方法適用于和窗口,和無法通過這種方法規避同源策略。逗號分隔的一個字符串,表明服務器支持的所有跨域請求的方法。 在制作oneday-music-player的時候要使用ajax向百度音樂的api發送請求,然后出現了XMLHttpRequest cannot load http://.... . No Access-Control-Allow-Origin header is pr...
摘要:請求服務器數據并規定回調函數為上面代碼通過動態添加元素,向服務器發出請求。另外假設向服務發送的請求是這樣的在這種情況下,是表示請求的請求參數,而是應用程序的回調函數的名稱。清單調用回調服務注意,我們使用作為回調函數名,而非真實的函數名。 同源策略 同源策略(Same origin policy),它是由Netscape提出的一個著名的安全策略。現在所有支持JavaScript的瀏覽器都...
摘要:我們看下跨域不生效的問題,首先拋出兩個問題我們如何設置又如何確定設置是否生效了首先,我們實現一個簡單的接口新建一個文件,將如下代碼復制進去,通過啟動服務,在本地就可以通過來訪問了我們創建的接口了環境安裝的教程網上有很多詳細的教程,本文不再贅 我們看下跨域不生效的問題,首先拋出兩個問題: 我們如何設置 cookie ? 又如何確定 cookie 設置是否生效了 ? 首先,我們實現一個...
摘要:方法和對應的方法定義定義重啟服務器,運行上面的程序。五添加支持實現跨域訪問當訪問時,你可能需要面對同源策略問題。錯誤如下一般來說,在服務器端,我們在響應中返回額外的訪問控制頭,實現跨域鏈接。 一、理解 REST REST(Representational State Transfer),中文翻譯叫表述性狀態轉移。是 Roy Thomas Fielding 在他2000年的博士論文中提出...
閱讀 1325·2021-10-27 14:14
閱讀 3579·2021-09-29 09:34
閱讀 2482·2019-08-30 15:44
閱讀 1729·2019-08-29 17:13
閱讀 2576·2019-08-29 13:07
閱讀 876·2019-08-26 18:26
閱讀 3349·2019-08-26 13:44
閱讀 3214·2019-08-26 13:37