在C ++ REST SDK中的http_listener上添加Access-Control-Allow-Origin

时间:2016-08-11 14:11:25

标签: javascript c++ cors cross-domain casablanca

我正在使用来自Microsoft C ++ REST SDK 1.3.1的web :: http :: experimental :: listener :: http_listener运行HTTP服务器,并尝试编写HTML和Javascript作为客户端与服务器进行交互。

几乎没有惊讶我得到了...... 跨源请求被阻止:同源策略不允许读取远程资源......(原因:CORS标题'访问控制 - 允许 - 来源'缺失)。

如何在http侦听器端(使用c ++代码)中放置 Access-Control-Allow-Origin:*

是否可以在C ++ REST 1.3.1中使用? 是否有解决方法,除了JSONP?

服务器

#include <cpprest/http_listener.h>
#include <cpprest/json.h>
using namespace web;
using namespace web::http;
using namespace web::http::experimental::listener;

http_listener httpSrv;
httpSrv->support(methods::GET, handle_get);

void handle_get(http_request request)
{
  const json::value response;
  request.reply(status_codes::OK, response);
}

客户端 使用jQuery v1.12.4的客户端(限于jQuery UI v1.12.0)

    $("button").click(function () {
        $.get(rest_url, function(data, status){
            console.log(status);
            console.log(data);
        });
    });

-----------------更新-----------------------

答案解答

SERVER

  http_listener httpSrv;
  httpSrv.support(methods::GET, handle_get);
  httpSrv.support(methods::POST, handle_post);
  httpSrv.support(methods::OPTIONS, handle_options);
  httpSrv.open().wait();

  //...........

  void handle_options(http_request request)
  {
    http_response response(status_codes::OK);
    response.headers().add(U("Allow"), U("GET, POST, OPTIONS"));
    response.headers().add(U("Access-Control-Allow-Origin"), U("*"));
    response.headers().add(U("Access-Control-Allow-Methods"), U("GET, POST, OPTIONS"));
    response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type"));
    request.reply(response);
  }

  void handle_get(http_request request)
  {        
    request.reply(status_codes::OK, ...);
  }

  void handle_post(http_request request)
  {
    json::value jsonResponse;

    request
      .extract_json()
      .then([&jsonResponse](pplx::task<json::value> task)
      {
        jsonResponse = process_request(task.get());
      })
     .wait();

    http_response response(status_codes::OK);
    response.headers().add(U("Access-Control-Allow-Origin"), U("*"));
    response.set_body(jsonResponse);
    request.reply(response);
  }  

客户端

  function requestREST(request/*json*/,onSuccess/*callback with json response*/) {    
    $.ajax({     
        type: "POST",
        url: "...",
        data: JSON.stringify(request),
        dataType: 'json',
        crossDomain: true,
        contentType: "application/json",
        success: function (response) {
            onSuccess(response);
        },
        timeout:3000,
        statusCode: {
            400: function (response) {
                alert('Not working!');
            },
            0: function (response) {
                alert('Not working!');
            }              
        }
    });

1 个答案:

答案 0 :(得分:5)

要在服务器端(C ++)添加标头,您需要修改用于发送响应的代码。

目前,您正在使用:

request.reply(status_codes::OK, response);

不是在单行中执行此操作,而是从空响应开始自己编写响应,添加所需的标题,设置实际的主体,然后将响应发送回客户端。

要构造一个空响应,我们可以使用以下函数:

web::http::http_response::http_response(http::status_code code)

the documentation所述,它将使用给定的状态代码构建响应,没有标题,也没有正文。

要访问响应的标题,我们可以使用以下函数:

web::http::http_response::headers()

返回的对象属于http_headers type,其中包含add function

web::http::http_headers::add(const key_type &name, const _t1 &value)

如果为响应提供了名称和标题值,此函数将为响应添加标题。

设置标题后,唯一剩下的就是正文。为此,响应包含set_body function

web::http::http_response::set_body(const json::value &body_data)

最后,完整的代码替换你的单行代码以创建一个空的响应,设置标题和正文然后将其发送回来看起来像:

http_response response(status_codes::OK);
response.headers().add(U("Access-Control-Allow-Origin"), U("*"));
response.set_body(jsonResponse);
request.reply(response);

请注意,在代码的最后一部分中,我使用U宏来创建目标平台类型的字符串文字。您可以在C++ Rest SDK FAQ中找到有关此U宏的更多信息。

关于使用OPTION HTTP谓词的预检请求,这些情况在这种情况下是预期的。默认情况下,C ++ REST SDK包含这些请求的默认实现。可以在the source code中检查默认实现:

void details::http_listener_impl::handle_options(http_request message)
{
    http_response response(status_codes::OK);
    response.headers().add(U("Allow"), get_supported_methods());
    message.reply(response);
}

它基本上返回200状态代码并添加服务器可以处理的受支持方法的列表。

如果要覆盖默认实现,例如添加预检请求(如Access-Control-Allow-MethodsAccess-Control-Allow-Headers)使用的某些特定标头,则需要添加一个特定的处理程序,就像您为{ {1}}和GET请求使用:

POST

使用通用处理程序处理web::http::experimental::listener::http_listener::support(const http::method &method, const std::function< void(http_request)> &handler) 请求时无法使用:

OPTION

如果我们看一下the source code,我们不能使用通用处理程序的原因是,如果方法没有特定的处理程序并使用web::http::experimental::listener::http_listener::support(const std::function<void(http_request)> &handler) HTTP动词(或TRACE),将调用C ++ REST SDK实现的默认处理程序:

OPTION