在HTTP POST请求中,Base64编码的文件变为空字符串

时间:2019-11-09 11:36:54

标签: angular typescript http

我正在尝试将对象数组发送到服务器,每个对象包含一个如下所示的base64编码的.png图像:

[
    {
        itemName: '...',
        itemType: '...',
        price: 123,
        purchaseUrl: '...',
        imageBase64: 'data:image/png;base64,...'
    },
    {...},
    {...}
]

我需要的所有数据都将一直保存到创建POST请求的位置,然后所有base64映像都变为空白。

{
  "newMerchandise": [
    {
      "imageBase64":"",
      "itemName":"asdasd",
      "itemType":"asdsad",
      "purchaseUrl":"asdsad",
      "price":123
    }
  ],
  "artistRef":"eddcc4ec-4e7c-4e0a-916e-3b845d9b713d"
}

发送http请求的Angular Injectable如下所示:

@Injectable()
export class MerchandiseApiService implements MerchandiseApiServiceInterface {
  private readonly _http: HttpClient;

  constructor(http: HttpClient) {
    this._http = http;
  }

  public addItems(newMerchandise: Array<NewMerchandiseUploadRequestClass>, artistRef: string): Observable<ApiResponse<string>> {
    console.log(newMerchandise); // base64 string exists still on each item.

    return this._http.post(`${environment.apiUrl}/api/merchandise/add-items`, {
        newMerchandise: newMerchandise,
        artistRef: artistRef
      })
        .pipe(
            map((response: MusicPortalApiResponse<string>): MusicPortalApiResponse<string> => {
              return {
                response: response.response,
                hasError: response.hasError,
                exception: response.exception
              }
            })
        )
  }
}

我尝试使用formData做同样的事情,我尝试了一种在将Base64字符串附加到FormData之前对其进行字符串化的方法,该方法可以工作,但随后我进行了如下修改:

"\"imageBase64"\":"\"data:image/png;base64,..."\",

这根本不干净。

我想知道这是否是标题文件?

Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 165
Content-Type: application/json
Host: localhost:5000
Origin: http://localhost:4200
Pragma: no-cache
Referer: http://localhost:4200/user/add-new-merchandise/eddcc4ec-4e7c-4e0a-916e-3b845d9b713d?artistRef=eddcc4ec-4e7c-4e0a-916e-3b845d9b713d
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36
X-AUTH-TOKEN: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJjMWM3OWRjNy1hMTdmLTRkNTktODBhNS1kNjM0YWVlNzAzNWYiLCJleHAiOjE1NzM3Mjk1MzMsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTAwMC8iLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjUwMDAvIn0.WTKdP6cFrUGrDq4YnX5IlqOkwP3-YRyhMrNpvQZzIWs

编辑

我已在服务器上的调试器中添加了此屏幕快照,该屏幕显示Base64字符串为空

enter image description here

1 个答案:

答案 0 :(得分:0)

所以我没有办法弄清楚发生了什么...但是,我的一个朋友只是建议使用文件上传指令,因此在进行大量重构并消除了cr * p吨的代码之后,我结束了:

import { Directive, ElementRef, forwardRef, HostListener, Renderer2 } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Directive({
    selector: '[fileUpload]',
    providers: [
        {
            provide: NG_VALUE_ACCESSOR,
            useExisting: forwardRef(() => FileUploadDirective),
            multi: true,
        }
    ]
})
export class FileUploadDirective implements ControlValueAccessor {
    private _onChange: Function;
    private _onTouched: Function;
    private readonly _renderer: Renderer2;
    private readonly _element: ElementRef;
    constructor(renderer: Renderer2, element: ElementRef) {
        this._renderer = renderer;
        this._element = element;
    }
    public registerOnChange(fn: Function): void {
        this._onChange = fn;
    }
    public registerOnTouched(fn: Function): void {
        this._onTouched = fn;
    }
    public setDisabledState(isDisabled: boolean): void {
        this._renderer.setProperty(this._element.nativeElement, 'disabled', isDisabled);
    }
    public writeValue(value: any): void {
        this._renderer.setProperty(this._element.nativeElement, 'value', value);
    }
    @HostListener('change', ['$event.target.value'])
    public onValueChange(): void {
        const file = this._element.nativeElement.files[0];
        const fileReader = new FileReader();
        fileReader.onload = (result): any => this._onChange(result.target['result']);
        fileReader.readAsDataURL(file);
    }
}

然后附加到我的文件上传表单输入中:

 <div class="my-2">
   <div>
     <label for="file-input">Choose an item image</label>
     <input id="file-input" class="file-input" accept="image/*" type="file" [formControlName]="newMerchandiseFormEnum.ITEM_IMAGE" fileUpload>
   </div>
</div>

这也意味着我在FormControl上也不必有任何不合理的逻辑,因此这是双赢。

import {Component, EventEmitter, Input, Output} from '@angular/core';
import {FormControl, FormGroup, Validators} from '@angular/forms';
import {NewMerchandiseFormEnum} from '../../../../models/form-enums/new-merchandise-form.enum';
import {Artist} from '../../../../models/domain/artist.class';
import {NewMerchandiseUploadRequest} from '../../../../models/api/new-merchandise-upload-request.class';

@Component({
  selector: 'app-new-merch-form',
  templateUrl: 'new-merchandise-form.component.html',
  styleUrls: ['new-merchandise-form.component.scss']
})

export class NewMerchandiseFormComponent {
  public newMerchandiseForm: FormGroup;
  public newMerchandiseFormEnum: typeof NewMerchandiseFormEnum = NewMerchandiseFormEnum;
  @Input() public artist: Artist;
  @Output() public onFormSubmitted: EventEmitter<NewMerchandiseUploadRequest>;

  constructor() {
    this.onFormSubmitted = new EventEmitter<NewMerchandiseUploadRequest>();

    this.newMerchandiseForm = new FormGroup({
      [this.newMerchandiseFormEnum.ITEM_NAME]: new FormControl('', [Validators.required]),
      [this.newMerchandiseFormEnum.ITEM_TYPE]: new FormControl('', [Validators.required]),
      [this.newMerchandiseFormEnum.ITEM_PRICE]: new FormControl('', [Validators.required]),
      [this.newMerchandiseFormEnum.ITEM_IMAGE]: new FormControl(null, [Validators.required]), // It just gets attached here as a string now. 
      [this.newMerchandiseFormEnum.PURCHASE_URL]: new FormControl('', [Validators.required]),
    })
  }

  public emitNewMerchForm(): void {
    this.onFormSubmitted.emit(this.newMerchandiseForm.value);
    this.newMerchandiseForm.reset();
  }
}