HTTP 请求
简单的 HTTP 请求
Midway 内置了一个简单的 HTTP 请求客户端,无需引入三方包即可使用。
默认 Get 请求,返回数据为 Buffer。
内置的 Http 客户端只提供最简单的能力,仅满足大部分的前端接口数据获取,如需复杂的功能,比如文件上传等,请使用其他的客户端,如 fetch,axios,got 等。
简单方法形式
import { makeHttpRequest } from '@midwayjs/core';
const result = await makeHttpRequest('http://127.1:7001/');
// Buffer.isBuffer(result.data)  => true
Get 请求,带上 Query,返回类型为 JSON。
import { makeHttpRequest } from '@midwayjs/core';
const result = await makeHttpRequest('http://127.1:7001/', {
  data: {
    a: 1,
    b: 2
  },
  dataType: 'json',	// 返回的数据格式
});
// typeof result.data => 'object'
// result.data.url => /?a=1&b=2
可以指定类型
import { makeHttpRequest } from '@midwayjs/core';
const result = await makeHttpRequest('http://127.1:7001/', {
  method: 'GET',
  dataType: 'json',
});
返回 text 格式。
import { makeHttpRequest } from '@midwayjs/core';
const result = await makeHttpRequest('http://127.1:7001/', {
  method: 'GET',
  dataType: 'text',
});
POST 请求并返回 JSON。
import { makeHttpRequest } from '@midwayjs/core';
const result = await makeHttpRequest('http://127.1:7001/', {
  method: 'POST',
  data: {
    a: 1,
    b: 2
  },
  dataType: 'json',
  contentType:'json', 	// 发送的 post 为 json
});
// result.data ...
注意,请不要在请求中直接返回 result 对象,result 对象是标准的 httpResponse,在大部分场景下无法被直接序列化,会抛出对象循环的错误。
设置请求超时时间。
import { makeHttpRequest } from '@midwayjs/core';
let err;
// 超时会报错,注意 catch
try {
  const result = await makeHttpRequest('http://127.1:7001/', {
    method: 'GET',
    dataType: 'text',
    timeout: 500,
  });
} catch (e) {
  err = e;
}
实例形式
import { HttpClient } from '@midwayjs/core';
const httpclient = new HttpClient();
const result = await httpclient.request('http://127.1:7001/');
// Buffer.isBuffer(result.data)  => true
和方法形式参数相同。
import { HttpClient } from '@midwayjs/core';
const httpclient = new HttpClient();
const result = await httpclient.request('http://127.1:7001/', {
  method: 'POST',
  data: {
    a: 1,
    b: 2
  },
  dataType: 'json',
  contentType:'json', 	// 发送的 post 为 json
});
// result.data ...
示例形式,可以复用创建出的对象,并且每次请求,都可以带上一些固定的参数,比如 header。
import { HttpClient } from '@midwayjs/core';
const httpclient = new HttpClient({
  headers: {
    'x-timeout': '5'
  },
  method: 'POST',
  timeout: 2000
});
// 每次都会带上 headers
const result = await httpclient.request('http://127.1:7001/');
Axios 支持
Midway 包裹了 axios 包,使得在代码中可以简单的使用 axios 接口。
和 axios 的一些关系如下:
- 接口完全一致
- 适配依赖注入写法,完整的类型定义
- 方便实例管理和配置统一
相关信息:
| 描述 | |
|---|---|
| 可用于标准项目 | ✅ | 
| 可用于 Serverless | ✅ | 
| 可用于一体化 | ✅ | 
| 包含独立主 框架 | ❌ | 
| 包含独立日志 | ❌ | 
安装依赖
$ npm i @midwayjs/axios@3 --save
或者在 package.json 中增加如下依赖后,重新安装。
{
  "dependencies": {
    "@midwayjs/axios": "^3.0.0",
    // ...
  },
}
引入组件
首先,引入 组件,在 configuration.ts 中导入:
import { Configuration } from '@midwayjs/core';
import * as axios from '@midwayjs/axios';
import { join } from 'path'
@Configuration({
  imports: [
    axios		// 导入 axios 组件
  ],
  importConfigs: [
    join(__dirname, 'config')
  ]
})
export class MainConfiguration {
}
然后在业务代码中即可注入使用。
使用默认 Axios 实例
接口和 axios 一致。
axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.options(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
axios.postForm(url[, data[, config]])
axios.putForm(url[, data[, config]])
axios.patchForm(url[, data[, config]])
使用示例:
import { HttpService } from '@midwayjs/axios';
@Provide()
export class UserService {
  @Inject()
  httpService: HttpService;
  async invoke() {
  	const url = 'https://midwayjs.org/resource/101010100.json';
    const result = await this.httpService.get(url);
    // TODO result
  }
}
配置默认 Axios 实例
HttpService 实例等价于 axios.create ,所以可以有一些配置参数,这些参数了 axios 本身的参数相同,我们可以在 src/config.default.ts 中配置它。
比如:
export default {
  // ...
  axios: {
    default: {
      // 所有实例复用的配置
    },
    clients: {
      // 默认实例的配置
      default: {
        baseURL: 'https://api.example.com',
        // `headers` are custom headers to be sent
        headers: {
          'X-Requested-With': 'XMLHttpRequest'
        },
        timeout: 1000, // default is `0` (no timeout)
        // `withCredentials` indicates whether or not cross-site Access-Control requests
        // should be made using credentials
        withCredentials: false, // default
      },
    }
  }
}
更多的参数可以参考 axios global config。
创建不同实例
和其他的服务多实例相同,配置不同的 key 即可。
export default {
  // ...
  axios: {
    default: {
      // 所有实例复用的配置
    },
    clients: {
      default: {
        // 默认实例
      },
      customAxios: {
        // 自定义实例
      }
    }
  }
}
使用方式如下:
import { HttpServiceFactory, HttpService } from '@midwayjs/axios';
import { InjectClient } from '@midwayjs/core';
@Provide()
export class UserService {
  @InjectClient(HttpServiceFactory, 'customAxios')
  customAxios: HttpService;
  async invoke() {
  	const url = 'https://midwayjs.org/resource/101010100.json';
    const result = await this.customAxios.get(url);
    // TODO result
  }
}
配置全局拦截器
如果使用的是默认的 Axios 实例,可以如下配置。
import { Configuration, IMidwayContainer } from '@midwayjs/core';
import * as axios from '@midwayjs/axios';
import { join } from 'path';
@Configuration({
  imports: [
    axios		// 导入 axios 组件
  ],
  importConfigs: [
    join(__dirname, 'config')
  ]
})
export class MainConfiguration {
  async onReady(container: IMidwayContainer) {
  	const httpService = await container.getAsync(axios.HttpService);
    httpService.interceptors.request.use(
      config => {
        // Do something before request is sent
        return config;
      },
      error => {
        // Do something with request error
        return Promise.reject(error);
      }
    );
  }
}
如果要给其他实例配置,可以参考下面的代码。
import { Configuration, IMidwayContainer } from '@midwayjs/core';
import * as axios from '@midwayjs/axios';
import { join } from 'path';
@Configuration({
  imports: [
    axios		// 导入 axios 组件
  ],
  importConfigs: [
    join(__dirname, 'config')
  ]
})
export class MainConfiguration {
  async onReady(container: IMidwayContainer) {
  	const httpServiceFactory = await container.getAsync(axios.HttpServiceFactory);
    const customAxios = httpServiceFactory.get('customAxios');
    customAxios.interceptors.request.use(
      config => {
        //...
      },
      error => {
        //...
      }
    );
  }
}
扩展 AxiosRequestConfig 类型
当前 Axios 库中 issue 有不少扩展 AxiosRequestConfig 类型的需求,但是 axios 本身并不支持扩展这个类型,其中的泛型仅限于设置 data 属性的类型。
Midway 中提供了 AxiosRequestConfig 的扩展,可以在组件层面增加新的属性。
// interface.ts
import '@midwayjs/axios';
declare module '@midwayjs/axios/dist/interface' {
  interface AxiosRequestConfig {
    retryDelay?: number;
    retry?: number;
  }
}
直接使用 Axios
@midayjs/axios导出了原始的axios实例,在非应用环境中可以直接使用。
import { Axios } from '@midwayjs/axios';
import { ReadStream, createWriteStream } from 'fs';
import { finished } from 'stream/promises';
async function download(url: string, filename: string) {
  const writer = await createWriteStream(filename);
  const res = Axios.get<ReadStream>(url, {
    responseType: 'stream',
  });
  res.data.pipe(writer);
  await finished(writer);
  return res;
}