JavaScript使用JsonP的XMLHttpRequest

29

我想向其他域名发送请求参数。

我已经知道跨脚本需要使用JsonP,我已经使用Jquery ajax使用了JsonP。

但是我不知道如何使用XMLHttpRequest进行跨脚本。

以下是我的基本XMLHttpRequest代码。

我猜我需要更改xhr.setRequestHeader()并添加解析代码。

请给我任何想法。

var xhr;
function createXMLHttpRequest(){    
    if(window.AtiveXObject){
        xhr = new ActiveXObject("Microsoft.XMLHTTP");
    }else{
        xhr = new XMLHttpRequest();
    }   
    var url = "http://www.helloword.com";   
}

function openRequest(){ 
    createXMLHttpRequest();
    xhr.onreadystatechange = getdata;
    xhr.open("POST",url,true);
    xhr.setRequestHeader("Content-Type",'application/x-www-form-urlencoded');
    xhr.send(data); 
}

function getdata(){
    if(xhr.readyState==4){
        if(xhr.status==200){
            var txt = xhr.responseText;
            alert(txt);
        }
    }   
}

可能是Ways to circumvent the same-origin policy的重复。 - Quentin
你不能使用JSONP进行POST请求。JSONP不是跨域请求的唯一方法。如果你需要进行跨域POST请求,请使用除JSONP之外的其他技术。 - Quentin
你的意思是如果我发送Get请求,这是可能的吗? - happenask
5个回答

71

JSONP不使用XMLHttpRequests。

JSONP的使用是为了克服XHR跨域限制。

相反,数据是通过脚本获取的。

function jsonp(url, callback) {
    var callbackName = 'jsonp_callback_' + Math.round(100000 * Math.random());
    window[callbackName] = function(data) {
        delete window[callbackName];
        document.body.removeChild(script);
        callback(data);
    };

    var script = document.createElement('script');
    script.src = url + (url.indexOf('?') >= 0 ? '&' : '?') + 'callback=' + callbackName;
    document.body.appendChild(script);
}

jsonp('http://www.helloword.com', function(data) {
   alert(data);
});

为了简化,此处未包含请求失败时的错误处理。如需要,请使用script.onerror


@ Paul Draper:我的回调函数没有被触发,请看一下我的代码:function pingUrlUsingJSONP(url, callback,onLoad,onError) { var tempCallback = 'jsonp_callback_' + Math.round(100000 * Math.random()); window[tempCallback] = function (data) { delete window[tempCallback]; document.body.removeChild(script); callback(data); }; var script = document.createElement('script'); script.type = 'text/html'; script.onerror = onError; script.onload = onLoad; script.async = true; script.src = url + (url.indexOf('?') >= 0 ? '&' : '?') + 'callback=' + tempCallback; document.body.appendChild(script); } - Anantha
@Paul Drapper,你能帮我一下吗?http://stackoverflow.com/questions/36302891/convert-jquery-ajax-to-pure-javascript-ajax 如果可以的话,谢谢。 - mmativ
为什么每次都要创建一个新的回调函数名? - RyanDay
1
@RyanDay,因为jsonp()可以使用不同的URL等进行调用。 - Paul Draper
这在我的端上可以工作,但它有多安全?如果每隔x秒使用它,它会失败吗?是否有PHP替代方案(例如curl)? - Toniq

1
对于 Google API,我被迫在 URL 中添加 callbackv=1.0 参数。如果没有 v=1.0 参数,我会遇到 CORB 错误(无论是我的版本还是其他答案代码 - 但是 jQuery 的 $.ajax 带有 dataType:"jsonp" 参数 - 所以我也加入了它并开始工作)。

Cross-Origin Read Blocking (CORB) 阻止跨域响应 https://ajax.googleapis.com/ajax/services/feed/load?callback=jsonp1555427800677,MIME 类型为 text/javascript。查看 https://www.chromestatus.com/feature/5629709824032768 获取更多细节。

下面是我的解决方案的 Promise 版本。

function jsonp(url) {
  return new Promise(function(resolve, reject) {
    var s = document.createElement('script');
    var f="jsonp"+(+new Date()), b=document.body;
    window[f] = d=>{ delete window[f]; b.removeChild(s); resolve(d); };
    s.src=`${url}${url.includes('?')?'&':'?'}callback=${f}&v=1.0`;
    b.appendChild(s);
  })
}

async function send() {
    let r = await jsonp("http://ajax.googleapis.com/ajax/services/feed/load");
    console.log(r);
}
<button onclick="send()">Send JSONP</button>


1

我知道你已经得到了答案,但如果还有其他人想要一个使用Promise的示例,这里有一个。

function jsonp(url) {
    return new Promise(function(resolve, reject) {
        let script = document.createElement('script')
        const name = "_jsonp_" + Math.round(100000 * Math.random());
        //url formatting
        if (url.match(/\?/)) url += "&callback="+name
        else url += "?callback="+name
        script.src = url;

        window[name] = function(data) {
            resolve(data);
            document.body.removeChild(script);
            delete window[name];
        }
        document.body.appendChild(script);
    });
}
var data = jsonp("https://www.google.com");
data.then((res) => {
    console.log(res);
});

尝试运行您的代码。它无法工作,因为google.com不返回JSONP(至少在那个URL上不是)。 - CertainPerformance

0
function JsonpHttpRequest(url, callback) {
    var e = document.createElement('script');
    e.src = url;
    document.body.appendChild(script); // fyi remove this element later /assign temp class ..then .remove it later
    //insetead of this you may also create function with  callback value and  use it instead
    window[callback] = (data) => {
        console.log(data);  // heres you data
    }
}
// heres how to use
function HowTouse(params) {
    JsonpHttpRequest("http://localhost:50702/api/values/Getm?num=19&callback=www", "www")
}

-4

使用XMLHttpRequest无法进行跨脚本攻击。如果您想在没有JQuery的情况下跨域,必须创建一个新的脚本节点并设置其src属性。


3
"使用XMLHttpRequest无法执行跨站脚本攻击"——不正确。 "如果你想要在没有JQuery的情况下跨域"——jQuery是无关紧要的,它只是一个库,它并不能做任何你自己无法完成的事情。 "你必须创建一个新的脚本节点并设置它的src属性"——不正确,还有其他方法可以进行跨源请求。而且,这只是制作JSONP请求的最后三分之一,你还没有解决定义函数或设置回调参数的问题。 - Quentin
你知道jQuery如何实现跨域请求吗?你怎样使用XMLHttpRequest发起跨域请求?Jsonp与XMLHttpRequest没有关系。 - limengjun
1
jQuery至少有三种不同的方法来进行跨域请求。使用XHR进行跨域请求的方法在我标记为重复的问题中有描述。 - Quentin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接