15 января, 2025

Multipart это просто

Недавно пришлось добавить авторизацию в сервисе, который принимает данные в виде form-data. Попробовал найти какую-то инструкцию, но ничего связного, в одном месте, не нашел. Так что, как обычно, записываю шпаргалку. Как из 1С отправить Post запрос с данными в формате multipart/form-data, или «данные формы».

Последовательность действий такая:

  • сгенерировать код который будет использоваться как граница блоков данных, boundary; разделитель будет состоять из двух тире, префикса и этого кода
  • данные — пары ключ-значение, записать в тело, разделяя строками с разделителем, внутри блока данных записывается имя данных и, через пустую строку, значение
  • последний разделитель записать с добавлением двух тире в конце
  • посчитать размер тела и сформировать заголовки, в заголовке нужно указать код, сгенерированный на первом шаге
  • отправить запрос

Теперь то же самое, в виде кода:

Function PostFormData(Conn, Path, Data, StatusCode=0, Err=Undefined) Export
	
	Err = Undefined;

	StatusCode = 0;
	
	If TypeOf(Data) <> Type("Structure") Then
			
		Err = "Unsupported form data for POST request";
		Return "";
	
	EndIf;
	
	Boundary = "Boundary" + StrReplace(String(New UUID()), "-", "");
	Splitter = "--" + Boundary;
	
	Body = New MemoryStream();
	Writer = New DataWriter(Body);
	For Each Param In Data Do
	
		Writer.WriteLine(Splitter);
		Writer.WriteLine("Content-Disposition: form-data; name=""" + Param.Key + """");
		Writer.WriteLine("");
		Writer.WriteLine(Param.Value);
	
	EndDo; 
	Writer.WriteLine("" + Splitter + "--");
	
	Writer.Close();
	Size = Format(Body.Size(), "NG=0");
	
	BinaryData = Body.CloseAndGetBinaryData();
	
	Headers = New Map;
	Headers.Insert("Content-Type", "multipart/form-data; boundary=" + Boundary);
	Headers.Insert("Content-Length", Size);
	
	Req = New HTTPRequest(Path, Headers);
	Req.SetBodyFromBinaryData(BinaryData);
		
	Try
	
		Resp = Conn.POST(Req);
	
	Except
		
		Err = ""+Path+": "+BriefErrorDescription(ErrorInfo());
		Return "";
	
	EndTry;
	
	StatusCode = Resp.StatusCode;
	
	Return Resp.GetBodyAsString();

EndFunction // PostFormData()

Функция принимает объект HTTPСоединение, путь и данные в виде структуры. Переменные StatusCode и Err нужны чтобы вернуть статус ответа и ошибку если что то пошло не так. Генерируется код на основании которого составляется разделитель Splitter, затем, с помощью объекта MemoryStream (ПотокВПамяти) записывается тело запроса.

В 1С 7.7 такого простого способа нет. Когда мне это было нужно, я добавил отправку мультипарт данных через вспомогательное внешнее приложение (ссылка).