最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript How to check if a URL is same origin as current page? - Stack Overflow

programmeradmin1浏览0评论

How can I check if a specific URL string is from the same origin/ host as the current page? For example, if I wanted to bind to links, but only prevent default on links to the same host...

How can I check if a specific URL string is from the same origin/ host as the current page? For example, if I wanted to bind to links, but only prevent default on links to the same host...

Share Improve this question asked Jul 13, 2015 at 2:48 JPollockJPollock 3,5584 gold badges27 silver badges37 bronze badges
Add a comment  | 

10 Answers 10

Reset to default 11

This should be safe to use nowadays:

function sameOrigin(a, b) {
    const urlA = new URL(a);
    const urlB = new URL(b);
    return urlA.origin === urlB.origin;
}

console.log(sameOrigin('https://stacksnippets.net', window.location))

The Origin definiton from the RFC 6454:

Roughly speaking, two URIs are part of the same origin (i.e., represent the same principal) if they have the same scheme, host, and port.

So we need to compare scheme, host, and port from two URIs, if they are the same, then these two URIs are the same origin.

A working code snippet:

function isOriginSameAsLocation(url) {
  var pageLocation = window.location;
  var URL_HOST_PATTERN = /(\w+:)?(?:\/\/)([\w.-]+)?(?::(\d+))?\/?/;
  var urlMatch = URL_HOST_PATTERN.exec(url) || [];
  var urlparts = {
      protocol:   urlMatch[1] || '',
      host:       urlMatch[2] || '',
      port:       urlMatch[3] || ''
  };

  function defaultPort(protocol) {
     return {'http:':80, 'https:':443}[protocol];
  }

  function portOf(location) {
     return location.port || defaultPort(location.protocol||pageLocation.protocol);
  }

  return !!(  (urlparts.protocol  && (urlparts.protocol  == pageLocation.protocol)) &&
              (urlparts.host     && (urlparts.host      == pageLocation.host))     &&
              (urlparts.host     && (portOf(urlparts) == portOf(pageLocation)))
          );
}

Here's a simple snippet of jQuery that will only preventDefault() on events called when clicking a link to an external URL.

The logic for assessing the URL is:

  1. Skip if local path
  2. Skip if full URL and the host is the same

I think that will work for a lot of simple use-cases.

$("a").on("click", function(e) {
  var hrefURL, pageURL;
  hrefURL = new URL(this.href);
  pageURL = new URL(window.location);
  if (!(href.startsWith("/") || hrefURL.host === pageURL.host)) {
    return e.preventDefault();
  }
});

you could parse each link, and then compare the "hostname" component to that returned by window.location.hostname.

;(function(){
    "use strict";
    
    var parseUrl = function(link){
        var a = document.createElement('a');
        a.href = link;
        return a;
    };
    
    var isSameOrigin = function(url1,url2) {
        return (url1.hostname === url2.hostname);
    };
    
    var localClick = function(ev){
        ev.preventDefault();
        alert('you clicked a local link');
    };
    
    var currentPage = window.location || window.document.location;

    document.addEventListener('DOMContentLoaded',function(){
        
      var els = document.querySelectorAll("a");
      for (var i=0;i<els.length;i++) {
          var el = els[i];        
          var othercell = el.parentNode.nextSibling.nextSibling;
          var isLocal = isSameOrigin( parseUrl(el.href), currentPage );
          othercell.innerHTML = isLocal;
          if (isLocal) {
             // now bind to the element
             el.addEventListener('click',localClick);  
          }
      }
    
    });
  
})();
th {
  text-align: left; background-color: #ddd;
}
<table>
  <tr>
      <th>link</th>
      <th>is same origin?</th>
  </tr>
  <tr>
      <td><a href="http://varsity.com">Varsity</a></td>
      <td></td>
  </tr>
  <tr>
      <td><a href="http://google.com">Google</a></td>
      <td></td>
  </tr>
  <tr>
      <td><a href="http://stacksnippets.net">Stack Snippets</a></td>
      <td></td>
  </tr>
  <tr>
      <td><a href="http://jsfiddle.net">JS Fiddle</a></td>
      <td></td>
  </tr>
  <tr>
      <td><a href="http://null.jsbin.com">JS Bin</a></td>
      <td></td>
  </tr>	  
</table>

Here is the same code on js bin:

http://jsbin.com/cigewa/1/edit?js,output

Here's a more modern version:

function sameOrigin(uri1, uri2=false){
  if(!uri2) uri2 = window.location.href;
  uri1 = new URL(uri1);
  uri2 = new URL(uri2);
  if(uri1.host !== uri2.host) return false;
  if(uri1.port !== uri2.port) return false;
  if(uri1.protocol !== uri2.protocol) return false;
  return true;
}

console.log(sameOrigin("https://google.com"));
console.log(sameOrigin("https://stacksnippets.net"));

Suppose you have the link for your current page is:

<a href="current.html" id="redirect">HomePage</a>  

And you are clicking on a random link:

<a href="random.html" id="rdm">HomePage</a>  

Then write a javascript function as:

function check(){
  if(document.getElementById("rdm").toString().indexOf("current")<0){
                 
    // do something  
         
    /*If it returns a negative value it means that the link we
     clicked does not contain the string 'current'(as our host is 
     current.html) i.e.the link is not our host link */
  else{
  
            // do something else
      }

Hope it helps.

while the answer from didxga should be less effort on the client side the answer from code monk brings me to a cleaner solution.

function doSomething(url) {
  // assuming we are in a function where we want to check the same origin
  var link = document.createElement('a');
  link.href = url;
  if (link.host !== location.host) {
    alert('url is invalid');
    return;
  }

  // do something...
}

Note that I'm using window.location with location. You may want to support browsers where this implementation is not working or have a location variable in a parent scope.

Here is a short but effective solution I came up with after discovering that the "check the host of an anchor tag" method doesn't work in IE11:

  function sameSite(uri) {
    var matches = uri.match(/^(https?:)?\/\/([^\/]+)/);
    if (!matches) {
      // If URI is not absolute or protocol-relative then it is always same-origin
      return true;
    }
    return window.location.host === matches[2];
  };

This returns true if the uri references the same site (same host and port) as the current page. Cross-browser implementation, valid at least back to IE11.

Regarding port numbers, this will match as long as the URIs are consistent about not explicitly specifying the port number when it is 80 (HTTP) or 443 (HTTPS), which is generally the case, so I didn't bother with special logic to handle a default port when it is explicit versus not explicit. I don't think that's likely to come up in practice, but there are other answers here that include it if you need it.

You can easily implement this system, like so (note: not tested, typed directly into the browser):

const checkURL(string) => {
    return new URL(string).host === location.host;
}
// to replace all <a> tags with the href "#invalid" if the hosts don't match
document.addEventListener("DOMContentLoaded", ()=>{
   document.querySelectorAll("a").forEach(tag => {
      // you don't have to have it go to a #*, but you could set it to a page that indicates the URL is not allowed.
      tag.href = checkURL(tag.href) ? tag.href : "#invalid";
  });
});
// to make links that go to the same host not do anything
document.addEventListener("DOMContentLoaded", ()=>{
    document.querySelectorALl("a").forEach(tag => {
        tag.href = checkURL(tag.href) ? "#" : tag.href
    })
})

You can get the current page's host IE example.com from http://example.com/hello-world with window.location.host. With that you can see if a string, IE the URL to test, contains that string.

   function sameOrigin( url ) {
        var host = window.location.host;
        var sameOrigin = url.indexOf(host);
        if ( sameOrigin >= 0 ) {
            return true;
        }
    }
发布评论

评论列表(0)

  1. 暂无评论