sdcsdv 发表于 2024-3-12 16:36:25

ajaxHooker拦截跨域问题求助

本帖最后由 sdcsdv 于 2024-3-12 17:41 编辑

> 本帖最后由 sdcsdv 于 2024-3-12 16:40 编辑

计划通过拦截axios请求,实现跨域访问,但发现axios跨域先被浏览器抓到了,请教如何实现拦截跨域访问?
!(data/attachment/forum/202403/12/163119w0m200yz0wz8y8mb.png)

前端代码:

```html
const onClick = async () => {
axios.get('https://www.baidu.com/', {})
    .then(res => {
      console.log(res);
    })
    .catch((e) => {
      console.log('获取数据失败');
    });
};
```

油猴代码:
```js
// ==UserScript==
// @name         ajaxHooker拦截-2024
// @namespace    http://tampermonkey.net/
// @version      0.1
// @descriptiontry to take over the world!
// @author       You
// @match      http://localhost:5173/*
// @grant      unsafeWindow
// @grant      GM_xmlhttpRequest
// @connect      *
// @require      https://scriptcat.org/lib/637/1.3.3/ajaxHooker.js
// @run-at       document-start
// ==/UserScript==



(function() {
    'use strict';
    ajaxHooker.hook(request => {
      console.log('request:', request);
      request.response = res => {
            const responseText = res.responseText; // 注意保存原数据
            res.responseText = new Promise(resolve => {
                setTimeout(() => {
                  //跨域访问
                  GM_xmlhttpRequest({
                        url: request.url,
                        method: request.method,
                        headers: request.headers,
                        data: request.body,
                        onload: function(res) {
                            console.log('res:', res);
                            //返回修改后数据
                            resolve(res);
                        },
                        onerror: function(error) {
                            console.log('error:', error);
                            reject(error);
                        }
                  });
                  //resolve('test');
                }, 2000);
            });
      };
    });
})();
```

cxxjackie 发表于 2024-3-12 16:36:26

你的意思是前端直接写跨域吗?那可以保存request.url的值,然后改一个同源url让其正常响应,再替换响应值:
ajaxHooker.hook(request => {
    const trueUrl = request.url;
    request.url = location.href;
    request.response = res => {
      res.responseText = new Promise(resolve => {
            GM_xmlhttpRequest({
                url: trueUrl,
                ....
            });
      });
    };
});
严格来说这不是最理想的方案,会多发生一次不必要的同源请求,因为ajaxHooker的主要目的是在原值上修改,而非整个替换原值,所以没有实现这部分特性。解决方案在那个库下面的回复中也有讨论(151楼),加入异步的话需要处理好事件的触发时机,通用的方案还得劫持更多事件,挺复杂的。

王一之 发表于 2024-3-13 09:45:09

cxxjackie 发表于 2024-3-12 22:32
你的意思是前端直接写跨域吗?那可以保存request.url的值,然后改一个同源url让其正常响应,再替换响应值: ...

给大佬补一下:

https://bbs.tampermonkey.net.cn/forum.php?mod=viewthread&tid=3284&page=16#pid76429

感觉如果可以拦截请求,然后返回自定义的内容还是挺爽的

cxxjackie 发表于 2024-3-13 22:17:15

王一之 发表于 2024-3-13 09:45
给大佬补一下:

https://bbs.tampermonkey.net.cn/forum.php?mod=viewthread&tid=3284&page=16#pid76429 ...

是可以做到的,再加一个参数就行了,只是我看着那堆缝缝补补的代码就头大,之前为了兼容各种奇怪的网站加了太多东西,比如我被迫采用defineProperty + Proxy结合的方案,到现在还有一点遗留问题没处理干净。
吐槽下XMLHttpRequest,这个接口太老旧了,调用繁琐,注入点也非常多,而且由于太繁琐了很多网站还喜欢把他包装一下,导致我的库要与他们共存就成了大问题,很多看起来一步到位的操作需要兜兜转转绕几步来完成。还有xhr实例可以被复用是最草的,相当于一个实例中发生了多次请求,这对异步劫持是个很大挑战,假设前端一边复用xhr一边自己劫持xhr,然后我的库可能还有多个实例在同时运行(多个脚本引用),这中间的兼容问题想想就头秃。反观fetch就好太多了,没有什么open、send这种莫名其妙的接口,一个Promise干净利落,劫持起来是真省心。
页: [1]
查看完整版本: ajaxHooker拦截跨域问题求助