在pact js中如何请求带有边界的多部分表单

问题描述 投票:0回答:1

考虑获取令牌的请求,例如:

const axios = require('axios');
const FormData = require('form-data');
let data = new FormData();
data.append('client_id', 'SOMEID');
data.append('client_secret', 'SOMESECRER');
data.append('scope', 'ouauth.scope.read');
data.append('grant_type', 'client_credentials');

let config = {
  method: 'post',
  maxBodyLength: Infinity,
  url: 'https://url/oauth2/token',
  headers: { 
    ...data.getHeaders()
  },
  data : data
};

axios.request(config)
.then((response) => {
  console.log(JSON.stringify(response.data));
})
.catch((error) => {
  console.log(error);
});

还有一个测试,例如

const  mockProvider = new Pact({
      consumer: 'some-consumer',
      provider: 'fake-provider',
      logLevel: 'debug',
    })

    mockProvider.addInteraction({
      uponReceiving: 'a request to get a new token',

      withRequest: {
        method: 'POST',
        path: '/oauth2/token',

        body: like({
          client_id: config.clientId,
          client_secret: config.secret,
          grant_type: 'client_credentials',
          scope: config.oAuthScope,
        }),

        headers: {
          'Content-Type': like('multipart/form-data'),
        },
      },
      willRespondWith: {
        status: 200,
        headers: {
          'Content-Type': 'application/json; charset=utf-8',
        },
        body: like(expectedToken),
      },
    })
  })

我不断收到错误消息

2023-12-05T12:42:09.017174Z 调试 tokio-runtime-worker pact_mock_server::hyper_server:请求不匹配:请求不匹配 匹配 - HTTP 请求(方法:POST,路径:/oauth2/token,查询:无, 标题:一些({“Content-Type”:[“multipart/form-data”]}),主体: Present(145 bytes) ) 0) $ -> 无法将预期正文解析为 MIME 多部分主体:“内容类型没有边界”

如果我省略了测试可以通过的主体,我将如何绕过边界?计算边界不起作用,因为它似乎会根据每个请求而改变

提前致谢

node.js typescript pact
1个回答
0
投票

pact-foundation/pact-js
问题 1140 所示,Pact JS 本身不支持将多部分表单数据与动态生成的边界相匹配。

原始的Axios请求正确发送多部分表单数据,但每个请求动态生成一个新的边界。这使得 Pact 交互中的匹配变得困难,因为 Pact 需要一致的格式来进行验证。

在 HTTP 中,

multipart/form-data
用于作为
POST
请求的一部分高效上传二进制数据或文件。 “边界”分隔符是一个字符串,用于分隔多部分数据的不同部分,以了解一个部分的结束位置和下一个部分的开始位置。
当发出
multipart/form-data
请求时,
Content-Type
标头包含此边界字符串。例如:
Content-Type: multipart/form-data; boundary=abc123

边界可以由客户端(例如 Web 浏览器或 Axios 等 HTTP 客户端库)“动态”生成。这样,边界字符串就不会意外出现在正在发送的数据中,这可能会破坏请求的格式。这意味着每次您发出 multipart/form-data 请求时,都会生成一个新的、唯一的边界字符串。

在 Pact 测试中定义预期请求时,您需要指定标头的外观,包括 

Content-Type

标头中的任何边界(如果请求为

multipart/form-data
)。但是......,由于边界是动态的并且随着每个请求而变化,因此在 Pact 测试中精确匹配它变得具有挑战性。
因此,出现“

no boundary in content-type

”错误。

您可以在测试中使用固定边界字符串。这允许您在 Pact 交互中显式设置并期望相同的边界字符串。

或者,如下所示,您可以尝试从 Axios 配置中提取实际的请求正文,其中包括动态生成的边界。通过在 Pact 交互中使用这个精确的主体,您可以避免必须预测或匹配动态边界的问题。

+------------------------+ +-------------------------+ +------------------+ | TypeScript Application | | Axios Request | | Pact Mock Server | | - Creates FormData | | - Sends multipart form | | - Matches Request | | - Appends form data | ----> | request with FormData | | with extracted | | - Sends request | | - Extracts request body | ----> | request body | | via Axios | | from config | | - Validates | +------------------------+ +-------------------------+ | interaction | +------------------+

您的文件(让我们将其命名为
OAuthTokenPactTest.ts

)将是:

import axios from 'axios';
import FormData from 'form-data';
import { Pact, Matchers } from '@pact-foundation/pact';

const { like } = Matchers;

const mockProvider = new Pact({
  consumer: 'some-consumer',
  provider: 'fake-provider',
  logLevel: 'debug',
});

const fetchToken = async () => {
  const data = new FormData();
  data.append('client_id', 'SOMEID');
  data.append('client_secret', 'SOMESECRER');
  data.append('scope', 'ouauth.scope.read');
  data.append('grant_type', 'client_credentials');

  const config = {
    method: 'POST',
    url: 'https://url/oauth2/token',
    headers: {
      'Content-Type': 'multipart/form-data',
    },
    data,
  };

  // Send the request
  const response = await axios.request(config);

  // Extract the request body
  const requestBody = response.config.data;

  mockProvider.addInteraction({
    uponReceiving: 'a request to get a new token',
    withRequest: {
      method: 'POST',
      path: '/oauth2/token',
      body: requestBody,
      headers: {
        'Content-Type': like('multipart/form-data'),
      },
    },
    willRespondWith: {
      status: 200,
      headers: {
        'Content-Type': 'application/json; charset=utf-8',
      },
      body: like(/* expectedToken */),
    },
  });
};

fetchToken();

关键的变化是使用 
response.config.data

提取实际的请求正文,而不是尝试在 Pact 交互中匹配多部分表单的动态边界。这绕过了处理边界问题的需要。

Pact 交互是通过实际请求正文设置的。这样,它就与 Axios 发送的内容相匹配,包括多部分表单数据结构和边界。

该文件应该位于专用于测试的目录中,特别是如果您遵循典型的 Node.js/TypeScript 项目结构。例如:

project-root/ │ ├── src/ # Source files for the application │ ├── app.ts # Main application file │ └── # Other application-specific files │ ├── tests/ # Test files │ ├── pact/ # Pact-specific tests │ │ ├── OAuthTokenPactTest.ts # The modified file for OAuth token Pact test │ │ └── # Other Pact test files │ └── # Other test files (unit, integration, etc.) │ ├── node_modules/ # Node.js modules │ ├── package.json # Project metadata and dependencies ├── tsconfig.json # TypeScript configuration └── ...

tests/pact/

是专门用于Pact相关测试的子目录。这就是

OAuthTokenPactTest.ts
所在的位置。由于其独特的设置和依赖性,最好将 Pact 测试分开。
    

© www.soinside.com 2019 - 2024. All rights reserved.