25

在实际尝试使用 ajax 方法之前,是否有一种“安全”的方法来检查同源策略是否适用于 URL?这是我所拥有的:

function testSameOrigin(url) {

    var loc = window.location,
        a = document.createElement('a');

    a.href = url;

    return a.hostname == loc.hostname &&
           a.port == loc.port &&
           a.protocol == loc.protocol;
}

这种工作,但它是一种基于维基百科文章的手动猜测。有没有更好的方法来预先检查跨域配额?jQuery 可以使用。

4

5 回答 5

16

Is there a "safe" way to check if the same origin policy applies to an URL before actually trying to use ajax methods? Here is what I have:

function testSameOrigin(url) {

    var loc = window.location,
        a = document.createElement('a');

    a.href = url;

    return a.hostname == loc.hostname &&
           a.port == loc.port &&
           a.protocol == loc.protocol;
}

This is a safe and reliable way of doing it, provided you are doing (or rather not doing) certain things.

This sort of works, but it’s kind of a manual guess based on the wikipedia article.

This should fully work under the "normal" circumstances. It will need to be modified if you are planning to use cross-domain scripting.

If you modify document.domain in your scripts, for example from "foo.example.com" and "bar.example.com" to "example.com" your testSameOrigin function would return false for "http://example.com", where in fact it should return true.

If you are planning on modifying document.domain, you can add simply add a check for that in your script.

If you are planning on using CORS (see the link above) to allow cross-domain communication, it will also return a false negative. But if you are using CORS, you will have a list of domains that you can communicate with, and you can add that list to this function as well.

Is there a better way of pre-checking cross domain allowance? jQuery is OK to use.

Probably not, although it may be worth mentioning that what you are seeing in the console from Steve's answer might be the "observer's dilemma" ... Those errors look like they are resulting from the console trying to inspect the other window, not necessarily from the script.

Assuming you're not messing with document.domain or using CORS, your original solution is probably better, as it doesn't need to make an extra request to determine whether the server is available or not. Even if you are doing some cross-domain scripting, modifying the function you have now to accommodate it is probably your best bet.

于 2012-03-05T16:02:12.250 回答
8

有趣的问题!我四处搜索,除了您发布的内容之外找不到任何其他内容,但是当我弄乱一些测试代码时,我确实遇到了这个问题。如果您只是想要一种简单的方法来测试 URL 而无需发出请求,我会按照您的方式进行。如果你不关心提出测试请求,你可以试试这个:

向您想要的任何 URL 发出简单的 ajax 请求:

var ajaxRequest = $.ajax({
  url: 'http://www.google.com',
  async: false
});

它返回一个jqXHR对象,然后您可以检查:

ajaxRequest.isRejected(); // or...
ajaxRequest.isResolved();

现在,唯一的问题是,isRejected()它将评估true页面未加载的每种情况(即 404 Not Found 等),但您可以通过以下方式检查状态代码:

ajaxRequest.status;

0当您尝试破坏同源策略时,上面的行似乎会返回,但在其他情况下它将返回适当的错误代码(再次,即 404)。

所以总结一下,也许你可以尝试做类似的事情:

function testSameOrigin(testUrl) {

  var ajaxRequest = $.ajax({
    url: testUrl,
    async: false
  });

  return ajaxRequest.isRejected() && ajaxRequest.status === 0;
}

无论如何都不是一个明确的答案,但我希望它可以帮助您弄清楚您在寻找什么!

于 2012-02-29T22:28:35.397 回答
3

也试试这个解决方案。

function csrfSafeMethod(method) {
  // these HTTP methods do not require CSRF protection
  return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

function sameOrigin(url) {
  // test that a given url is a same-origin URL
  // url could be relative or scheme relative or absolute
  var host = window.document.location.host; // host + port
  var protocol = window.document.location.protocol;
  var srOrigin = '//' + host;
  var origin = protocol + srOrigin;
  // Allow absolute or scheme relative URLs to same origin
  return (url === origin || url.slice(0, origin.length + 1) === origin + '/') ||
    (url === srOrigin || url.slice(0, srOrigin.length + 1) === srOrigin + '/') ||
    // or any other URL that isn't scheme relative or absolute i.e relative.
    !(/^(\/\/|http:|https:).*/.test(url));
}

// if you want to check before you make a call
if (!csrfSafeMethod(data.type) && sameOrigin(data.url)) {
  // ...
}

// or if you want to set csrf token
$.ajax({
  beforeSend: function (xhr, settings) {
    if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
      xhr.setRequestHeader("X-CSRFToken", getCookie("csrftoken"));
    }
  }
});
于 2015-01-26T16:22:47.027 回答
0

基于 Dagg Nabbit 的回答,这似乎更完整:

function sameOrigin(url) {
    var loc = window.location, a = document.createElement('a')
    a.href = url

    return a.hostname === loc.hostname &&
           a.port === loc.port &&
           a.protocol === loc.protocol &&
           loc.protocol !== 'file:'
}

我能想到的注意事项:

于 2014-07-07T20:31:04.517 回答
0

另一种执行跨域脚本的方法是使用JSON-P。您也可以阅读这篇文章。否则,同源策略不允许跨域脚本。

于 2012-02-28T23:50:02.783 回答