如何通过 Preflight Request 从 javascript 调用 REST Webservice?
Posted
技术标签:
【中文标题】如何通过 Preflight Request 从 javascript 调用 REST Webservice?【英文标题】:How to invoke REST Webservice from the javascript by Preflight Request? 【发布时间】:2013-12-30 21:31:39 【问题描述】:我正在尝试从 javascript 本身调用位于另一个域中的服务。我可以请求跨域服务。但我无法从服务中检索信息。一些我如何被同源政策阻止。请帮我找出代码中的错误。
我的客户端 Javascript 代码:
var requestJsonData;
function crossDomainCall() ** It will be called by button click **
requestJsonData = createCORSRequest('POST', 'IPAddress/servicePath');
if (requestJsonData)
requestJsonData.onreadystatechange = handler;
requestJsonData.send();
else
alert('Cross Domain Call is not invoked');
function handler(evtXHR)
if(requestJsonData.readyState == 4)
if(requestJsonData.status == 200)
var response = requestJsonData.responseText;
else
alert(" Invocation Errors Occured " + requestJsonData.readyState + " and the status is " + requestJsonData.status);
else
alert("currently the application is at " + requestJsonData.readyState);
function createCORSRequest(method, url)
var xhr;
xhr = new XMLHttpRequest();
if ("withCredentials" in xhr)
xhr.open(method, url, true);
xhr.setRequestHeader('X-PINGOTHER', 'pingpong');
else if (typeof XDomainRequest != "undefined")
xhr = new XDomainRequest();
xhr.open(method, url);
else
xhr = null;
return xhr;
服务代码:
@OPTIONS
@Path("/servicePath")
@Produces("*/*")
@Consumes("*/*")
public Response corsRequest()
Response response = null;
ResponseBuilder builder = null;
builder = Response.ok();
builder.header("Access-Control-Allow-Headers", "X-PINGOTHER");
builder.header("Access-Control-Max-Age","1728000");
builder.header("Access-Control-Allow-Origin","Origin_Ip_Address");
builder.header("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
builder.header("Content-Type","text/plain");
builder.header("Connection", "Keep-Alive");
response = builder.build();
System.out.println("Exited from Options method");
return response;
@POST
@Path("/servicePath")
@Produces("application/json")
public String drawRegions()
System.out.println("Entered inside Post method");
// Some calculation to arrive jsonObject.
return jsonObject;
从代码中,我收到了以下结果。
OPTIONS 方法请求和响应标头
请求标头:
选项 /SolartisGeoCodeLookUpService/Service/drawRegions HTTP/1.1
主机:Cross_Domain_IP_Address
用户代理:Mozilla/5.0 (X11; Linux x86_64; rv:25.0) Gecko/20100101 Firefox/25.0
接受:text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
接受语言:en-US,en;q=0.5
接受编码:gzip、deflate
来源:Origin_IP_Address
访问控制请求方法:POST
访问控制请求标头:x-pingother
连接:保持活动
编译指示:无缓存
缓存控制:无缓存
响应标头
HTTP/1.1 200 正常
服务器:Apache-Coyote/1.1
访问控制允许标头:X-PINGOTHER
连接:保持活动状态
访问控制允许来源:Origin_IP_Address
访问控制最大年龄:1728000
访问控制允许方法:POST、GET、OPTIONS
内容类型:文本/纯文本
内容长度:0
日期:格林威治标准时间 2013 年 12 月 12 日星期四 12:39:27
响应缓存标头
来自缓存的响应标头
Access-Control-Allow-Head... X-PINGOTHER 访问控制允许方法... POST、GET、OPTIONS 访问控制最大年龄 1728000 连接保活 内容长度 0 内容类型 text/plain 日期 2013 年 12 月 12 日星期四 12:39:27 GMT 服务器 Apache-Coyote/1.1 访问控制允许原始 Origin_IP_Address
POST 方法请求和响应标头
请求标头
POST /servicePath HTTP/1.1
主机:crossDomain_IP_Address
用户代理:Mozilla/5.0 (X11; Linux x86_64; rv:25.0) Gecko/20100101 Firefox/25.0
接受:text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
接受语言:en-US,en;q=0.5
接受编码:gzip、deflate
X-PINGOTHER:乒乓球
来源:Origin_IP_Address
连接:保持活动
编译指示:无缓存
缓存控制:无缓存
内容长度:0
响应标头
HTTP/1.1 200 正常
服务器:Apache-Coyote/1.1
内容类型:文本/json
内容长度:128
日期:格林威治标准时间 2013 年 12 月 12 日星期四 12:39:27
附加信息 从 javascript 中调用了两次处理程序方法。第一次,它提出“当前应用程序处于 2” - readyState 值。第二次出现“Invocation Errors Occured 4(readyState value) and status code is 0 (response status code)”。第二次响应明确表示,调用服务已被同源策略停止。但我不知道如何克服这个问题并且必须访问资源。请通过更正我的代码来帮助我。
【问题讨论】:
你能用 Logger.INFO() 代替 System.out 吗?我认为您的 CORS 实施应该有问题。你是否在 web.xml 中包含了你的 CORSFilter 实现包? @sivatumma:我没明白你的意思。如何在 web.xml 中包含 CORSFilter 实现?为什么我们在 web.xml 中需要它? 假设两个域都由您编码,为了允许跨源请求,您的服务必须实现ContainerResponseFilter
及其public ContainerResponse filter(ContainerRequest req, ContainerResponse contResp) ...
方法。您还应该让您的 web.xml
知道这是它应该服务的 servlet。
【参考方案1】:
与其在 javascript 中处理 X 域调用,不如为您的应用程序开发一个本地服务来使用另一个域中的 Web 服务,然后您可以从 javascript 调用您的本地服务。
我还建议您使用 jQuery 来执行跨域 Ajax 调用,请参阅此链接:http://www.pureexample.com/jquery/cross-domain-ajax.html。
没有必要直接处理 XHR,因为你有 jQuery 为你做这件事。
希望对你有帮助,
问候。
【讨论】:
我觉得从本地服务拨打电话可以解决。当我们可以从 javascript 调用其他域时,为什么我们不使用它?如果我遗漏了什么,请清除我的视图。 此技术也称为网络代理,是常见的做法,请查看此链接developer.yahoo.com/javascript/howto-proxy.html。关于 javascript Xdomain 调用,有些域支持这种类型的调用,它可以在他们的 Web 服务器中配置,就像这里所说的 bionicspirit.com/blog/2011/03/24/cross-domain-requests.html。以上是关于如何通过 Preflight Request 从 javascript 调用 REST Webservice?的主要内容,如果未能解决你的问题,请参考以下文章
Angular 6 - Spring MVC :: Options preflight request throws 500 internal Server Error
HTTP协议详解(HyperText Transfer Protocol 超文本传输协议)访问控制(CORS) (OPTIONS预请求preflight request)浏览器同源策略
解决Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight 跨域问题