input发送a.jax_Java EE 7 / JAX-RS 2.0 – REST上的CORS
input發(fā)送a.jax
Java EE REST應(yīng)用程序在開箱即用的開發(fā)機器上通常可以很好地運行,在該機器上,所有服務(wù)器端資源和客戶端UI都指向“ localhost”或127.0.0.1。 但是,當涉及跨域部署時(當REST客戶端不再與托管REST API的服務(wù)器位于同一域時),則需要一些解決方法。 本文是關(guān)于Java EE 7 / JAX-RS 2.0 REST API時如何使跨域或更廣稱為跨域資源共享(又稱為CORS)的。 本文無意討論有關(guān)瀏覽器和其他與安全性相關(guān)的機制,您可能會在其他網(wǎng)站上找到它。 但是我們真正想要在這里實現(xiàn)的是再次使事情盡快運作。
問題是什么?
演示Java EE 7(JAX-RS 2.0)REST服務(wù)
在本文中,我將僅為演示目的而編寫一個基于Java EE 7 JAX-RS 2.0的簡單REST Web服務(wù)和客戶端。
在這里,我將定義一個接口,以REST服務(wù)的url路徑以及為HTTP響應(yīng)接受的HTTP方法和MIME Type對其進行注釋。
RESTCorsDemoResourceProxy.java的代碼:
package com.developerscrappad.intf;import java.io.Serializable; import javax.ejb.Local; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response;@Local @Path( "rest-cors-demo" ) public interface RESTCorsDemoResourceProxy extends Serializable {@GET@Path( "get-method" )@Produces( MediaType.APPLICATION_JSON )public Response getMethod();@PUT@Path( "put-method" )@Produces( MediaType.APPLICATION_JSON )public Response putMethod();@POST@Path( "post-method" )@Produces( MediaType.APPLICATION_JSON )public Response postMethod();@DELETE@Path( "delete-method" )@Produces( MediaType.APPLICATION_JSON )public Response deleteMethod(); }RESTCorsDemoResource.java的代碼:
package com.developerscrappad.business;import com.developerscrappad.intf.RESTCorsDemoResourceProxy; import javax.ejb.Stateless; import javax.json.Json; import javax.json.JsonObject; import javax.json.JsonObjectBuilder; import javax.ws.rs.core.Response;@Stateless( name = "RESTCorsDemoResource", mappedName = "ejb/RESTCorsDemoResource" ) public class RESTCorsDemoResource implements RESTCorsDemoResourceProxy {@Overridepublic Response getMethod() {JsonObjectBuilder jsonObjBuilder = Json.createObjectBuilder();jsonObjBuilder.add( "message", "get method ok" );JsonObject jsonObj = jsonObjBuilder.build();return Response.status( Response.Status.OK ).entity( jsonObj.toString() ).build();}@Overridepublic Response putMethod() {JsonObjectBuilder jsonObjBuilder = Json.createObjectBuilder();jsonObjBuilder.add( "message", "get method ok" );JsonObject jsonObj = jsonObjBuilder.build();return Response.status( Response.Status.ACCEPTED ).entity( jsonObj.toString() ).build();}@Overridepublic Response postMethod() {JsonObjectBuilder jsonObjBuilder = Json.createObjectBuilder();jsonObjBuilder.add( "message", "post method ok" );JsonObject jsonObj = jsonObjBuilder.build();return Response.status( Response.Status.CREATED ).entity( jsonObj.toString() ).build();}@Overridepublic Response deleteMethod() {JsonObjectBuilder jsonObjBuilder = Json.createObjectBuilder();jsonObjBuilder.add( "message", "delete method ok" );JsonObject jsonObj = jsonObjBuilder.build();return Response.status( Response.Status.ACCEPTED ).entity( jsonObj.toString() ).build();} }RESTCorsDemoResource中的代碼簡單明了,但是請記住,這只是一個演示應(yīng)用程序,在其業(yè)務(wù)邏輯中沒有有效的目的。 RESTCorsDemoResource類實現(xiàn)在接口RESTCorsDemoResourceProxy中定義的方法簽名。 它有幾種方法可以通過特定的HTTP方法(例如GET,PUT,POST和DELETE)處理傳入的HTTP請求,并且在方法結(jié)束時,在完成該過程后將返回一條簡單的JSON消息。
不要忘了下面的web.xml ,當路徑檢測到“ / rest-api / * ”(例如http:// <host>:<port>)時,該web.xml會告訴應(yīng)用服務(wù)器將其視為任何傳入HTTP請求的REST API調(diào)用。 / AppName / rest-api / get-method /)。
web.xml中的內(nèi)容:
javax.ws.rs.core.Application1javax.ws.rs.core.Application/rest-api/*部署方式
讓我們將以上內(nèi)容打包到一個名為RESTCorsDemo.war的war文件中,并將其部署到與Java EE 7兼容的應(yīng)用服務(wù)器中。 在我這方面,我正在使用默認設(shè)置在Glassfish 4.0上運行此程序,該默認設(shè)置位于具有公共域的計算機上developerscrappad.com
部署后,REST服務(wù)的URL應(yīng)如下所示:
| RESTCorsDemoResourceProxy.getMethod() | http://developerscrappad.com/RESTCorsDemo/rest-api/rest-cors-demo/get-method/ |
| RESTCorsDemoResourceProxy.postMethod() | http://developerscrappad.com/RESTCorsDemo/rest-api/rest-cors-demo/post-method/ |
| RESTCorsDemoResourceProxy.putMethod() | http://developerscrappad.com/RESTCorsDemo/rest-api/rest-cors-demo/put-method/ |
| RESTCorsDemoResourceProxy.deleteMethod() | http://developerscrappad.com/RESTCorsDemo/rest-api/rest-cors-demo/delete-method/ |
HTML REST客戶端
在本地計算機上,我將創(chuàng)建一個簡單HTML頁面,以通過以下方式調(diào)用已部署的REST服務(wù)器資源:
rest-test.html的代碼:
<!DOCTYPE html> <html><head><title>REST Tester</title><meta charset="UTF-8"></head><body><div id="logMsgDiv"></div><script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script><script type="text/javascript">var $ = jQuery.noConflict();$.ajax( {cache: false,crossDomain: true,dataType: "json",url: "http://developerscrappad.com:8080/RESTCorsDemo/rest-api/rest-cors-demo/get-method/",type: "GET",success: function( jsonObj, textStatus, xhr ) {var htmlContent = $( "#logMsgDiv" ).html( ) + "<p>" + jsonObj.message + "</p>";$( "#logMsgDiv" ).html( htmlContent );},error: function( xhr, textStatus, errorThrown ) {console.log( "HTTP Status: " + xhr.status );console.log( "Error textStatus: " + textStatus );console.log( "Error thrown: " + errorThrown );}} );$.ajax( {cache: false,crossDomain: true,dataType: "json",url: "http://developerscrappad.com:8080/RESTCorsDemo/rest-api/rest-cors-demo/post-method/",type: "POST",success: function( jsonObj, textStatus, xhr ) {var htmlContent = $( "#logMsgDiv" ).html( ) + "<p>" + jsonObj.message + "</p>";$( "#logMsgDiv" ).html( htmlContent );},error: function( xhr, textStatus, errorThrown ) {console.log( "HTTP Status: " + xhr.status );console.log( "Error textStatus: " + textStatus );console.log( "Error thrown: " + errorThrown );}} );$.ajax( {cache: false,crossDomain: true,dataType: "json",url: "http://developerscrappad.com:8080/RESTCorsDemo/rest-api/rest-cors-demo/put-method/",type: "PUT",success: function( jsonObj, textStatus, xhr ) {var htmlContent = $( "#logMsgDiv" ).html( ) + "<p>" + jsonObj.message + "</p>";$( "#logMsgDiv" ).html( htmlContent );},error: function( xhr, textStatus, errorThrown ) {console.log( "HTTP Status: " + xhr.status );console.log( "Error textStatus: " + textStatus );console.log( "Error thrown: " + errorThrown );}} );$.ajax( {cache: false,crossDomain: true,dataType: "json",url: "http://developerscrappad.com:8080/RESTCorsDemo/rest-api/rest-cors-demo/delete-method/",type: "DELETE",success: function( jsonObj, textStatus, xhr ) {var htmlContent = $( "#logMsgDiv" ).html( ) + "<p>" + jsonObj.message + "</p>";$( "#logMsgDiv" ).html( htmlContent );},error: function( xhr, textStatus, errorThrown ) {console.log( "HTTP Status: " + xhr.status );console.log( "Error textStatus: " + textStatus );console.log( "Error thrown: " + errorThrown );}} );</script></body> </html>在這里,我將jQuery的ajax對象用于帶有已定義選項的REST Services調(diào)用。 rest-test.html的目的是使用適當?shù)腍TTP方法調(diào)用REST服務(wù)URL,并獲取響應(yīng)作為JSON結(jié)果以供以后處理。 我不會在這里詳細介紹,但是如果您想了解更多有關(guān)$ .ajax調(diào)用選項的信息,可以訪問jQuery的文檔站點 。
當我們運行rest-test.html時會發(fā)生什么?
當我在Firefox瀏覽器上運行rest-test.html文件時,配備了Firebug插件 ,以下是我得到的屏幕截圖。
屏幕快照:Firebug控制臺選項卡結(jié)果
屏幕截圖:Firebug的“ Net”選項卡結(jié)果
如您所見,當我在控制臺選項卡上選中時,“ / rest-api / rest-cors-demo / get-method / ”和“ / rest-api / rest-cors-demo / post-method / ”返回了正確的HTTP狀態(tài),但我可以絕對確定該方法未在遠程Glassfish應(yīng)用服務(wù)器上執(zhí)行,REST服務(wù)調(diào)用只是被繞過,在rest-test.html客戶端上,它直接進入了$ .ajax錯誤回調(diào)。 當我如圖所示檢查Firebug網(wǎng)絡(luò)選項卡時,“ / rest-api / rest-cors-demo / put-method / ”和“ / rest-api / rest-cors-demo / delete-method / ”如何處理?在其中一個屏幕截圖中,瀏覽器通過觸發(fā)OPTIONS作為HTTP方法而不是PUT和DELETE發(fā)送了預檢請求。 這種現(xiàn)象與服務(wù)器端和瀏覽器的安全有關(guān)。 我在頁面底部還編譯了與此相關(guān)的其他一些網(wǎng)站。
如何使CORS在Java EE 7 / JAX-RS 2.0(通過攔截器)中工作
為了在客戶端和服務(wù)器端REST資源上進行跨域調(diào)用或簡稱為CORS,我創(chuàng)建了兩個JAX-RS 2.0攔截器類,一個實現(xiàn)了ContainerRequestFilter ,另一個實現(xiàn)了ContainerResponseFilter 。
ContainerResponseFilter中的其他HTTP標頭
瀏覽器將需要一些其他的HTTP標頭來響應(yīng)它,以進一步驗證服務(wù)器端資源是否允許跨域/跨域資源共享以及它允許??的安全級別或限制級別。 這些標頭在啟用CORS時開箱即用。
Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true Access-Control-Allow-Methods: GET, POST, DELETE, PUT這些額外的HTTP標頭集可以通過將其包含在實現(xiàn)ContainerResponseFilter的類中而包含在返回到瀏覽器時的HTTP響應(yīng)中。
**但請注意:擁有“訪問控制允許來源:*”將允許接受所有呼叫,而與客戶端的位置無關(guān)。 有多種方法可以進一步限制此限制,因為您只希望服務(wù)器端僅允許來自特定域的REST服務(wù)調(diào)用。 請查看頁面底部的相關(guān)文章。
RESTCorsDemoResponseFilter.java的代碼:
package com.developerscrappad.filter;import java.io.IOException; import java.util.logging.Logger; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerResponseContext; import javax.ws.rs.container.ContainerResponseFilter; import javax.ws.rs.container.PreMatching; import javax.ws.rs.ext.Provider;@Provider @PreMatching public class RESTCorsDemoResponseFilter implements ContainerResponseFilter {private final static Logger log = Logger.getLogger( RESTCorsDemoResponseFilter.class.getName() );@Overridepublic void filter( ContainerRequestContext requestCtx, ContainerResponseContext responseCtx ) throws IOException {log.info( "Executing REST response filter" );responseCtx.getHeaders().add( "Access-Control-Allow-Origin", "*" );responseCtx.getHeaders().add( "Access-Control-Allow-Credentials", "true" );responseCtx.getHeaders().add( "Access-Control-Allow-Methods", "GET, POST, DELETE, PUT" );} }處理瀏覽器預檢請求HTTP方法:選項
實現(xiàn)ContainerResponseFilter的RESTCorsDemoResponseFilter類僅解決了部分問題。 我們?nèi)匀槐仨毺幚頌g覽器對PUT和DELETE HTTP方法的飛行前請求。 大多數(shù)流行的瀏覽器的基礎(chǔ)飛行前請求機制都以某種方式工作,即它們使用OPTIONS作為HTTP方法發(fā)送一個請求,只是為了測試水域。 如果服務(wù)器端資源確認請求的路徑URL,并允許接受PUT或DELETE HTTP方法進行處理,則服務(wù)器端通常將必須發(fā)送HTTP Status 200(OK)響應(yīng)(或任何20x HTTP Status)返回到瀏覽器,然后瀏覽器將實際請求作為HTTP方法PUT或DELETE發(fā)送給瀏覽器。 但是,此機制必須由開發(fā)人員手動實現(xiàn)。 因此,我以RESTCorsDemoRequestFilter的名稱實現(xiàn)了一個新類, 該類實現(xiàn)了以下針對此機制顯示的ContainerRequestFilter 。
RESTCorsDemoRequestFilter.java的代碼:
package com.developerscrappad.filter;import java.io.IOException; import java.util.logging.Logger; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.PreMatching; import javax.ws.rs.core.Response; import javax.ws.rs.ext.Provider;@Provider @PreMatching public class RESTCorsDemoRequestFilter implements ContainerRequestFilter {private final static Logger log = Logger.getLogger( RESTCorsDemoRequestFilter.class.getName() );@Overridepublic void filter( ContainerRequestContext requestCtx ) throws IOException {log.info( "Executing REST request filter" );// When HttpMethod comes as OPTIONS, just acknowledge that it accepts...if ( requestCtx.getRequest().getMethod().equals( "OPTIONS" ) ) {log.info( "HTTP Method (OPTIONS) - Detected!" );// Just send a OK signal back to the browserrequestCtx.abortWith( Response.status( Response.Status.OK ).build() );}} }結(jié)果
之后, RESTCorsDemoResponseFilter和RESTCorsDemoRequestFilter包含在應(yīng)用程序中并進行部署。 然后,我再次在瀏覽器上重新運行rest-test.html 。 結(jié)果,JAX-RS 2.0應(yīng)用程序很好地處理了來自不同位置的具有不同HTTP方法GET,POST,PUT和DELETE的所有HTTP請求。 下面的屏幕截圖是我的瀏覽器成功執(zhí)行的HTTP請求。 Firebug控制臺和NET Tab的這些結(jié)果是預期的:
屏幕快照:Firebug控制臺選項卡
屏幕截圖:Firebug的“ Net”選項卡
最后的話
在攔截諸如啟用CORS之類的方案的REST相關(guān)請求和響應(yīng)時,JAX-RS 2.0攔截器非常方便。 如果您正在為Java項目使用REST庫的特定實現(xiàn),例如Jersey或RESTEasy ,請檢查如何具體實現(xiàn)請求和響應(yīng)攔截器,應(yīng)用上述技術(shù),您應(yīng)該可以獲得相同的結(jié)果。 相同的原理幾乎相同。
好吧,希望本文能幫助您解決Java EE 7 / JAX-RS 2.0 REST項目上的跨域或CORS問題。
感謝您的閱讀。
相關(guān)文章:
- http://en.wikipedia.org/wiki/Cross-origin_resource_sharing
- http://www.html5rocks.com/zh-CN/tutorials/cors/
- http://www.w3.org/TR/cors/
- https://developer.mozilla.org/en/docs/HTTP/Access_control_CORS
翻譯自: https://www.javacodegeeks.com/2014/11/java-ee-7-jax-rs-2-0-cors-on-rest.html
input發(fā)送a.jax
總結(jié)
以上是生活随笔為你收集整理的input发送a.jax_Java EE 7 / JAX-RS 2.0 – REST上的CORS的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑版应用宝下载(电脑版应用宝下载速度慢
- 下一篇: 易租网租电脑是真的吗(易租网租电脑是真的