摘要:這個(gè)過程是瀏覽器會(huì)發(fā)一次請(qǐng)求,詢問服務(wù)器是否允許代碼如下完了以后,客戶端就可以順利請(qǐng)求服務(wù)器接口了。
此文講解在RESTful API中跨域問題在項(xiàng)目中如何處理的!
CORS 是 Cross Origin Resource Sharing 的縮寫, 定義了瀏覽器和服務(wù)器間共享內(nèi)容的新方式,通過它瀏覽器和服務(wù)器可以安全地進(jìn)行跨域訪問,它是 JSONP 的現(xiàn)代繼任 者。服務(wù)器上的 CORS 配置可以精細(xì)地指定允許跨域訪問的條件:來源域、HTTP 方法、請(qǐng)求頭、內(nèi)容類型等等。并 且,CORS 讓 XMLHttpRequest 也可以跨域,我們可以像往常一樣編寫 AJAX 調(diào)用代碼。所有現(xiàn)代瀏覽器都支持 CORS,所以你應(yīng)該可以放心地使用它,只有在需要兼容老舊瀏覽器的場(chǎng)合,才用 JSONP做fallback。支持 CORS 的瀏覽器在嘗試進(jìn)行跨域 XMLHttpRequest 時(shí),會(huì)先發(fā)出一個(gè)“事前檢查”,就是一個(gè)OPTIONS 請(qǐng)求,其中會(huì)包括一些有用的請(qǐng)求頭:
Access-Controll-Request-Headers: accept, content-type Access-Controll-Request-Method: POST
接著服務(wù)器會(huì)做出響應(yīng):
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
最后瀏覽器會(huì)根據(jù)服務(wù)器的響應(yīng)頭,判斷請(qǐng)求是否在服務(wù)器規(guī)定的范圍內(nèi)。比如來源是否在 Access-Control-Allow- Origin 里,HTTP 方法是不是在 Access-Control-Allow-Methods 里面,有沒有不在 Allow-Headers 里面的請(qǐng)求頭。如果以上條件都符合,那么瀏覽器就會(huì)放行這次請(qǐng)求,并且在Access-Control-Max-Age 指定的時(shí)間內(nèi)(單位是秒,以上設(shè)置的是 20 天)不需要再進(jìn)行這種“事前檢查”。
在以上服務(wù)器響應(yīng)頭中,Access-Control-Allow-Headers 不可以使用通配符。所以如果你要允許所有請(qǐng)求頭,不妨把瀏覽器發(fā)來的 Access-Control-Request-Header 直接返回。
事實(shí)上,如果跨域請(qǐng)求是“簡(jiǎn)單請(qǐng)求”,也就是 HTTP 方法為 GET、HEAD、POST,請(qǐng)求體的 MIME Type 是以下其中一種:application/x-www-form-urlencoded、multipart/form-data 或者text/plain,并且沒有自定義的請(qǐng)求頭。這時(shí)瀏覽器只根據(jù)請(qǐng)求頭中的 Origin 和服務(wù)器返回的Access-Control-Allow-Origin 就可以判斷了。但我們是 RESTful API,請(qǐng)求體是application/json,所以只能用上面那種“事前檢查”的方式。另外,利用 CORS 還可以在跨域請(qǐng)求中發(fā)送 Cookie,這個(gè)特性是很有用的。只需要為 XMLHttpRequest 對(duì)象設(shè)置 withCredentials 屬性:
var xhr = new XMLHttpRequest(); xhr.withCredentials = true; java在resteasy中設(shè)置 response.getOutputHeaders().putSingle("Access-Control-Allow-Credentials",true);
但這種情況下,就不能指定 Access-Control-Allow-Origin: *,而是必須指定一個(gè)來源,比如http://mydomain.com。
java 操作:resteasy 設(shè)置如下
先提供options請(qǐng)求,告訴客戶端允許客戶端可以帶什么樣的頭信息過來。比如:
客戶要封裝一個(gè)復(fù)雜json數(shù)據(jù)來請(qǐng)求服務(wù)器,這時(shí)服務(wù)器需要需要允許客戶端頭信息中的content-type 為application/json。這個(gè)過程是瀏覽器會(huì)發(fā)一次options請(qǐng)求,詢問v服務(wù)器是否允許
代碼如下:
@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(); }
完了以后,客戶端就可以順利請(qǐng)求服務(wù)器(接口:creatorunion/works)了。
但這樣寫有個(gè)問題,每個(gè)接口都需要去設(shè)置,由于在項(xiàng)目中使用了netty作為容器需要在netty容器里添加自定義handlers來統(tǒng)一處理resteasy &netty的淵源請(qǐng)參考:
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(); }
第一個(gè)
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); } }
第二個(gè)
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); } }
對(duì)于nodejs做如下配置可允許資源的跨域訪問:
設(shè)置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(); });
補(bǔ)充:
參考https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/66026.html
摘要:但是這種方法適用于和窗口,和無法通過這種方法規(guī)避同源策略。逗號(hào)分隔的一個(gè)字符串,表明服務(wù)器支持的所有跨域請(qǐng)求的方法。 在制作oneday-music-player的時(shí)候要使用ajax向百度音樂的api發(fā)送請(qǐng)求,然后出現(xiàn)了XMLHttpRequest cannot load http://.... . No Access-Control-Allow-Origin header is pr...
摘要:請(qǐng)求服務(wù)器數(shù)據(jù)并規(guī)定回調(diào)函數(shù)為上面代碼通過動(dòng)態(tài)添加元素,向服務(wù)器發(fā)出請(qǐng)求。另外假設(shè)向服務(wù)發(fā)送的請(qǐng)求是這樣的在這種情況下,是表示請(qǐng)求的請(qǐng)求參數(shù),而是應(yīng)用程序的回調(diào)函數(shù)的名稱。清單調(diào)用回調(diào)服務(wù)注意,我們使用作為回調(diào)函數(shù)名,而非真實(shí)的函數(shù)名。 同源策略 同源策略(Same origin policy),它是由Netscape提出的一個(gè)著名的安全策略?,F(xiàn)在所有支持JavaScript的瀏覽器都...
摘要:我們看下跨域不生效的問題,首先拋出兩個(gè)問題我們?nèi)绾卧O(shè)置又如何確定設(shè)置是否生效了首先,我們實(shí)現(xiàn)一個(gè)簡(jiǎn)單的接口新建一個(gè)文件,將如下代碼復(fù)制進(jìn)去,通過啟動(dòng)服務(wù),在本地就可以通過來訪問了我們創(chuàng)建的接口了環(huán)境安裝的教程網(wǎng)上有很多詳細(xì)的教程,本文不再贅 我們看下跨域不生效的問題,首先拋出兩個(gè)問題: 我們?nèi)绾卧O(shè)置 cookie ? 又如何確定 cookie 設(shè)置是否生效了 ? 首先,我們實(shí)現(xiàn)一個(gè)...
摘要:方法和對(duì)應(yīng)的方法定義定義重啟服務(wù)器,運(yùn)行上面的程序。五添加支持實(shí)現(xiàn)跨域訪問當(dāng)訪問時(shí),你可能需要面對(duì)同源策略問題。錯(cuò)誤如下一般來說,在服務(wù)器端,我們?cè)陧憫?yīng)中返回額外的訪問控制頭,實(shí)現(xiàn)跨域鏈接。 一、理解 REST REST(Representational State Transfer),中文翻譯叫表述性狀態(tài)轉(zhuǎn)移。是 Roy Thomas Fielding 在他2000年的博士論文中提出...
閱讀 1398·2021-10-27 14:14
閱讀 3660·2021-09-29 09:34
閱讀 2541·2019-08-30 15:44
閱讀 1790·2019-08-29 17:13
閱讀 2630·2019-08-29 13:07
閱讀 955·2019-08-26 18:26
閱讀 3406·2019-08-26 13:44
閱讀 3272·2019-08-26 13:37