让代码能访问外网


让代码能访问外网

众所周知,国内是没有办法直接访问外网的,而我们查东西很多时候都会用Google来进行搜索(百度的SEO不太友好,每次查对应内容,官网经常会在挺后面),比如使用v2ray等工具。

但是使用工具的话,代码也没法fq,即使配置了系统代理。

这个还是写一个爬虫小工具时,看的一个Python爬虫库的原理,后面慢慢尝试才知道的。顺带一提,Python比较特殊,可以直接访问外网。

问题复现(pipe流式数据处理)

首先,这边使用https模块访问www.baidu.com,看看实际效果。

1
2
3
4
5
6
7
8
9
import https from 'https';
import fs from 'fs';

const endpoint = 'https://www.baidu.com';

https.get(endpoint, (res) => {
res.pipe(process.stdout);
res.pipe(fs.createWriteStream('./index.html'));
})

上面使用pipe方法的原因:

https模块的回调函数中的res对象是一个可读流,可以通过流式数据的处理方式处理响应体。而pipe方法是Nodejs中用于流式数据处理的一个方法,\color{red}{将可读流中的数据直接传递给可写流进行处理}。

res.pipe(process.stdout)则是将向响应体直接传递给标准输出流,即直接将响应体输出到命令行窗口中。process.stdout是一个可写流,可以将数据输出到终端。

效果:

而将百度换成谷歌就会出现问题:(已经开了系统代理)

socks-proxy-agent

因为我用的是v2ray来代理的,所以就需要一个工具来实现使用socks代理来发送请求,这个时候就可以使用socks-proxy-agent库。

详细内容可以查看官方介绍:socks-proxy-agent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import https from 'https';
import fs from 'fs';
import url from 'url';
import { SocksProxyAgent } from 'socks-proxy-agent';

const endpoint = 'https://www.google.com';
const opts = url.parse(endpoint); // 将url字符串转换成 { protocol: 'https:', hostname: 'www.google.com', ... }的对象形式

const proxy = 'socks://127.0.0.1:10808'; // Socks代理连接到连接到电脑上开的v2ray代理
const agent = new SocksProxyAgent(proxy);
opts.agent = agent;

https.get(opts, (res) => {
res.pipe(process.stdout);
res.pipe(fs.createWriteStream('./index.html'));
})

因为我们需要配置代理(在代理里),所以就不能够像前面一样,https.get的第一个参数应该是一个{ protocol: 'https:', hostname: '[www.google.com'](http://www.google.com'), ... }形式的对象,这样子配置代理只需要给这个对象添加agent属性即可,所以用到了url模块将url字符串转换。

socks-proxy-agent的应用也很简单,引入SocksProxyAgent构造函数,并且将电脑上开的代理地址作为参数传给构造函数即可。因为我是本地开的代理,所以ip会是127.0.0.1,而端口则可以自己查看。设置 -> 参数设置

效果:

使用webpack的解决方案:(没测试过,感觉以后用得上,其他框架配置也类似)

解决webpack-dev-server由于网络问题出现ETIMEDOUT-CSDN博客

fetch版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import fetch from 'node-fetch';
import { SocksProxyAgent } from 'socks-proxy-agent';
import fs from 'fs';
// 创建代理对象
const proxy = 'socks://127.0.0.1:10808';;
const agent = new SocksProxyAgent(proxy);

// 设置 fetch 请求选项
const url = 'https://www.google.com';
const options = {
method: 'GET',
agent: agent
};

// 发起 fetch 请求
fetch(url, options)
.then(res => {
res.body.pipe(process.stdout);
res.body.pipe(fs.createWriteStream('./index.html'));
})
.catch(err => console.error(err));

fetch版本的res对象并不是可读流,res.body才是,可以从stream中引入Readable测试。

Node18内置 fetch

Node18以及之后的版本中,都内置了fetch api。但是,在浏览器环境下,fetch是不支持直接设置代理的,因为浏览器限制了跨域请求和安全性问题,不允许通过脚本设置底层网络层信息。而Node18之后内置的fetch API也不支持直接设置代理。

可以使用https模块或者使用node-fetch来设置。

浅尝一下内置的fetch API。

1
2
3
4
5
6
7
8
9
10
11
12
import { Readable } from 'stream';

fetch('https://www.clzczh.top')
.then(res => {
console.log(res instanceof Readable); // false
console.log(res.body instanceof Readable); // false

return res.text();
})
.then(data => {
console.log(data);
})

需要注意:原生fetchresres.body都不是可读流,所以需要用fetchres.text()那一套来获取响应体。

更多

流 - 权威指南(貌似是浏览器端的,但是感觉挺有用的,记录一下。)

(4条消息) 解决webpack-dev-server由于网络问题出现ETIMEDOUT-CSDN博客


文章作者: 赤蓝紫
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 赤蓝紫 !
评论
  目录