使用 JSONP 或 CORS 的跨域 JavaScript 调用

Posted

技术标签:

【中文标题】使用 JSONP 或 CORS 的跨域 JavaScript 调用【英文标题】:Cross Domain JavaScript calls using JSONP or CORS 【发布时间】:2017-09-17 05:24:33 【问题描述】:

如何在客户端和服务端使用jsonp和CORS在网页上实现跨域ajax调用。

例如在www.mytestsite.com上,要对www.otherdestinationserver.com进行ajax调用,如何使用JSONPCORS实现?

【问题讨论】:

请更具体一些。你想在你的服务器上实现这个,或者访问其他远程 api 的? 【参考方案1】:

在研究并浏览了所有其他帖子后,我终于找到了一些解决方案。我正在为这两种方法写答案。

1.仅在不使用 CORS 的情况下使用 JSONP:如果使用 JSONP,则始终需要更改服务器端以使用 callback 方法获取 json 响应。此外,callback 方法必须存在于 javascript 中才能执行。所以在下面的例子中,当我们调用目标 url 时,如果我们得到响应为myCallBackMethod( "customerData": "name": "testName", "age": 26 ),那么我们必须有一个名为myCallBackMethodjavascript method。使用jsonp,cookies can also be shared across domains

在这种方法中,不需要在目标服务器的响应中设置任何标头来允许请求的域。 本示例中使用的callback 方法是myCallBackMethod。此名称可以是任何名称,javascriptresponse jsonp string must match 中的名称除外

客户端/javascript:

function makeTheCall(queryString) 
    var destinationUrl = "www.otherdestinationserver.com";
    $.ajax(
      type: 'GET',
      url: destinationUrl + queryString,
      dataType: 'jsonp',
      jsonpCallback: 'myCallBackMethod',
      async: false, // this is by default false, so not need to mention
      crossDomain: true // tell the browser to allow cross domain calls.
     // success: successResopnse, jsonpCallback will call the successCallback
     // error: failureFunction jsonp does not support errorCallback. So cannot use this 
    );
  

  window.myCallBackMethod = function(data) 
   successResponse(data);
  
  
  successResponse = function(data) 
  //functionality goes here;
  
  
  // the json response from the server when calling the url must be in the below format only.
  
  myCallBackMethod( "customerData":  "name": "testName", "age": 26  )

2。仅使用不带 JSONP 且不带 URL 重写的 CORS:如果使用 CORS,则始终有一个 need to make changes on server and client/javascript。在这种方法中,no need to get any callback 方法作为 json 响应的一部分。回复must be a pure json。但是,在目标服务器上进行适当的代码更改以让请求通过。所以需要在response对象中设置header

客户端/javascript:

function makeTheCall(queryString) 
    var destinationUrl = "www.otherdestinationserver.com";
    $.ajax(
      type: 'GET',
      url: destinationUrl + queryString,
      dataType: 'json', // use json only, not jsonp
      crossDomain: true, // tell browser to allow cross domain.
      success: successResopnse,
      error: failureFunction
    );
  
  
  successResponse = function(data) 
  //functionality goes here;
  

  failureFunction = function(data) 
  //functionality goes here;
  

在服务器上,添加以下标头。

httpServletResponse.setHeader("Access-Control-Allow-Origin", "*"); // Here need to give the origin url (the url in the address bar of the page which is making request). Using * means allow any value
但是,将上述代码添加到服务器后,服务器和请求的页面之间不会共享任何 cookie。要在请求的页面和服务器上获取 cookie,我们需要在客户端和服务器上添加以下属性。

在客户端/javascript:

xhrFields: 
    'withCredentials': true // tell the client to send the cookies if any for the requested domain
    

在服务器上:

httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
这些更改允许客户端和服务器共享 cookie。 但是,如果在响应中使用标头Access-Control-Allow-Credentials,则标头Access-Control-Allow-Origin 的值会受到限制。它应该never be * if we want to use Access-Control-Allow-Credentials header。因此,请给出准确的域名。

服务器更新:

httpServletResponse.setHeader("Access-Control-Allow-Origin", "www.mytestsite.com"); // Give the origin url (the url in the address bar of the page which is making request).

最终客户端/javascript:(仅限 CORS 方法)

function makeTheCall(queryString) 
    var destinationUrl = www.otherdestinationserver.com;
    $.ajax(
      type: 'GET',
      url: destinationUrl + queryString,
      dataType: 'json', // use json only, not jsonp
      crossDomain: true, // tell browser to allow cross domain
      xhrFields: 
         'withCredentials': true // tell the client to send the cookies if any for the requested domain
      ,
      success: successResopnse,
      error: failureFunction
    );
  
  
  successResponse = function(data) 
  //functionality goes here;
  

  failureFunction = function(data) 
  //functionality goes here;
  

最终服务器代码:(仅限 CORS 方法)

httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpServletResponse.setHeader("Access-Control-Allow-Origin", "www.mytestsite.com");

3.仅将 CORS 与 URL 重写过滤器设置 RESPONSE HEADERS 一起使用:

如果应用程序使用 url 重写过滤器(大多数 Web 应用程序都使用),这将使实现更容易。在上面的方法 2 中,不要遵循 Final Server 代码:(仅限 CORS 方法),而是按照下面的 url 在 xml 处更改(url 重写过滤器)。

How to set origin or referer value which we got from request into the response-header using urlrewritefilter

下面粘贴相同的代码以供快速参考。

<rule enabled="true" match-type="regex">
<name>Enabling CORS Headers</name>
<from>^/path/someMorePath.*$</from>
<condition name="origin" operator="equal">([a-z]+)</condition>
<set type="response-header" name="Access-Control-Allow-Origin">%1</set>
<set type="response-header" name="Access-Control-Allow-Credentials">true</set>

【讨论】:

第三种解决方案(其中 Access-Control-Allow-Origin 的值设置为 Origin 的值)基本上将 CORS 保护冲下马桶。它相当于 Access-Control-Allow-Origin: *.您必须在此处明确列出允许的域,而不是从请求中动态获取它们。【参考方案2】:

如果你不能控制服务器端,你可以像我一样解决

仅限客户端。

如果您可以控制服务器端,则可以使用服务器端解决方案。我不在这里讨论它。

仅在客户端,解决方法是

使用数据类型:'jsonp',

   async function get_ajax_data()

       var _reprojected_lat_lng = await $.ajax(

                                type: 'GET',

                                dataType: 'jsonp',

                                data: ,

                                url: _reprojection_url,

                                error: function (jqXHR, textStatus, errorThrown) 

                                    console.log(jqXHR)

                                ,

                                success: function (data) 

                                    console.log(data);



                                    // note: data is already json type, you just specify dataType: jsonp

                                    return data;

                                

                            );





  // function               

【讨论】:

以上是关于使用 JSONP 或 CORS 的跨域 JavaScript 调用的主要内容,如果未能解决你的问题,请参考以下文章

服务器端http请求是否具有相同的跨域策略?

Ajax跨域:jsonp还是CORS

JSONP && CORS

CORS跨域

web项目中的跨域问题解决方法

AJAX学习笔记2:XHR实现跨域资源共享(CORS)以及和JSONP的对比