使用Sendgrid和NodeJs Google Cloud Function从Angular 6应用发出的Http POST请求-错误405

时间:2018-12-21 19:43:37

标签: angular google-cloud-platform google-cloud-functions sendgrid-api-v3

我正在尝试使用最小有效负载从Angular 6应用程序中使用Sendgrid的电子邮件。发布请求时,使用Google Cloud Function从浏览器中出现错误405:

  

https://MyCloudFunctions/httpEmail 405

     

从原点“ https://MyCloudFunctions/httpEmail”到“ http://localhost:4200”处对XMLHttpRequest的访问已被CORS策略阻止:对预检请求的响应未通过访问控制检查:否'Access-Control-Allow-来源的标头出现在请求的资源上。

云功能日志显示:

  

错误:Promise.resolve.then(/user_code/index.js:26:23)在process._tickDomainCallback(internal / process / next_tick.js:135:7)仅接受POST请求

云功能代码

const sendgrid = require('sendgrid');
const client = sendgrid("MyAPI_KEY");

function parseBody(body) {
  var helper = sendgrid.mail;
  var fromEmail = new helper.Email(body.from);
  var toEmail = new helper.Email(body.to);
  var subject = body.subject;
  var content = new helper.Content('text/html', body.content);
  var mail = new helper.Mail(fromEmail, subject, toEmail, content);
  return  mail.toJSON();
}

exports.sendgridEmail = (req, res) => {
    res.setHeader("Access-Control-Allow-Origin", "*");
    res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    res.setHeader("Content-Type", "application/json");
  return Promise.resolve()
    .then(() => {
      if (req.method !== 'POST') {
        const error = new Error('Only POST requests are accepted');
        error.code = 405;
        throw error;
      }

      // Build the SendGrid request to send email
      const request = client.emptyRequest({
        method: 'POST',
        path: '/v3/mail/send',
        body: getPayload(req.body),
      });

      // Make the request to SendGrid's API
      console.log(`Sending email to: ${req.body.to}`);
      return client.API(request);
    })
    .then(response => {
      if (response.statusCode < 200 || response.statusCode >= 400) {
        const error = Error(response.body);
        error.code = response.statusCode;
        throw error;
      }

      console.log(`Email sent to: ${req.body.to}`);

      // Forward the response back to the requester
      res.status(response.statusCode);
      if (response.headers['content-type']) {
        res.set('content-type', response.headers['content-type']);
      }
      if (response.headers['content-length']) {
        res.set('content-length', response.headers['content-length']);
      }
      if (response.body) {
        res.send(response.body);
      } else {
        res.end();
      }
    })
    .catch(err => {
      console.error(err);
      const code =
        err.code || (err.response ? err.response.statusCode : 500) || 500;
      res.status(code).send(err);
      return Promise.reject(err);
    });
}

**更新:简化的TS文件** 角度TS文件

    import { Component, OnInit } from '@angular/core';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { Router } from '@angular/router';

@Component({
  selector: 'app-contact',
  templateUrl: './contact.component.html',
  styleUrls: ['./contact.component.css']
})
export class ContactComponent implements OnInit {

  //constructor(private sendgridService: SendgridService){}
  constructor(private _http: HttpClient, private router: Router) { }
  ngOnInit() { }

  sendEmail() {

    let url = `https://us-central1-probalance-214005.cloudfunctions.net/httpEmail?sg_key=MY_API_KEY`
    let body = {
      "personalizations": [
        {
          "to": [
            {
              "email": "myemail@example.com",
              "name": "Postman"
            }
          ],
          "subject": "Success"
        }
      ],
      "from": {
        "email": "myemail2@example.com",
        "name": "Angular App"
      },
      "reply_to": {
        "email": "myemail@example.com",
        "name": "Test"
      },
      "content": [
        {
          "type": "text/plain",
          "value": "Request Successful 001!"
        }
      ]
    };

    let httpOptions = {
      headers: new HttpHeaders({
        'Content-Type': 'application/json',
      })
    };
    console.log("Payload:")
    console.log(url)
    console.log(body);
    console.log(httpOptions.headers)

    return this._http.post(url, body, httpOptions)
      .toPromise()
      .then(res => {
        console.log(res)
      })
      .catch(err => {
        console.log(err)
      })

  }
}

角度HTML文件

<button type="submit" id="submit" class="btn btn-primary (click)="sendEmail()">Sendgrid </button>

1 个答案:

答案 0 :(得分:1)

几件事:

  • Access-Control-Allow-Origin是响应头。因此,它应该在服务器代码中设置,而不是在用Angular编写的客户端代码中设置。
  • 由于设置了Content-Type,浏览器将发送OPTIONS请求而不是POST。因此,请确保已启用OPTIONS请求类型,并且服务器的Access-Control-Allow-Header中允许使用Content-Type。

您可以在此处了解有关CORS问题的更多信息:https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS