ActionDispatch::ParamsParser::ParseError 用于字符串请求负载

ActionDispatch::ParamsParser::ParseError for String Request Payload

我收到了来自 API 的标准请求。它看起来像这样:

它的内容类型和长度是:

但是当它到达我的 Rails 服务器时,Rails 响应

我之所以提出这个问题,是因为相同的请求似乎在 SCORM Cloud 的服务器上有效。如果我向他们上传完全相同的内容,并在调试器中观察它,我会看到它发送了一个具有相同请求有效负载的 application/json 语句,但没有 unexpected token 错误。

Rails application/json 请求是否必须以不同于其他服务器的特定方式编写?有没有合适的方法在机架中间件中重写这一行来防止这个错误?

更新

javascript :

function _TCDriver_XHR_request (lrs, url, method, data, callback, ignore404, extraHeaders) {
_TCDriver_Log("_TCDriver_XHR_request: " + url);
var xhr,
    finished = false,
    xDomainRequest = false,
    ieXDomain = false,
    ieModeRequest,
    title,
    ticks = ['/', '-', '\', '|'],
    location = window.location,
    urlParts,
    urlPort,
    result,
    extended,
    until,
    fullUrl = lrs.endpoint + url
;

urlParts = fullUrl.toLowerCase().match(/^(.+):\/\/([^:\/]*):?(\d+)?(\/.*)?$/);

// add extended LMS-specified values to the URL
if (lrs.extended !== undefined) {
    extended = [];
    for (var prop in lrs.extended) {
        if(lrs.extended[prop] != null && lrs.extended[prop].length > 0){
            extended.push(prop + "=" + encodeURIComponent(lrs.extended[prop]));
        }
    }
    if (extended.length > 0) {
        fullUrl += (fullUrl.indexOf("?") > -1 ? "&" : "?") + extended.join("&");
    }
}

//Consolidate headers
var headers = {};
headers["Content-Type"] = "application/json";
headers["Authorization"] = lrs.auth;
if (extraHeaders !== null) {
    for (var headerName in extraHeaders) {
        headers[headerName] = extraHeaders[headerName];
    }
}

//See if this really is a cross domain
xDomainRequest = (location.protocol.toLowerCase() !== urlParts[1] || location.hostname.toLowerCase() !== urlParts[2]);
if (! xDomainRequest) {
    urlPort = (urlParts[3] === null ? ( urlParts[1] === 'http' ? '80' : '443') : urlParts[3]);
    xDomainRequest = (urlPort === location.port);
}

//If it's not cross domain or we're not using IE, use the usual XmlHttpRequest
if (! xDomainRequest || typeof XDomainRequest === 'undefined') {
    _TCDriver_Log("_TCDriver_XHR_request using XMLHttpRequest");
    xhr = new XMLHttpRequest();
    xhr.open(method, fullUrl, callback != null);
    for (var headerName in headers) {
        xhr.setRequestHeader(headerName, headers[headerName]);
    }
}
//Otherwise, use IE's XDomainRequest object
else {
    _TCDriver_Log("_TCDriver_XHR_request using XDomainRequest");
    ieXDomain = true;
    ieModeRequest = _TCDriver_GetIEModeRequest(method, fullUrl, headers, data);
    xhr = new XDomainRequest ();
    xhr.open(ieModeRequest.method, ieModeRequest.url);
}

Does a Rails application/json request have to be written a certain way that differs from other servers?

据我所知没有。

Is there a proper way to rewrite this line in Rack Middleware to prevent this error?

可能有一种方法是的,甚至可能没有机架中间件,尽管在没有实际请求的情况下很难帮助您。

Rails 在这里是 "helpful" 并假设客户端正确使用 "Content-Type" 并传递一个实际匹配该内容类型的值。换句话说,请求中的负载必须是可解析的 JSON,并且传递的值无效 JSON。

当您实施内部 API 并非旨在实现最大互操作性时,它这样做是完全合理的。 Rails 不知道的是 LRS 的文档存储应该是 "dumb" 并且基本上允许客户端将它想要的东西推入并取出它想要的东西,这就是 SCORM Cloud 接受的原因请求,基本上它只是存储内容类型和内容,然后根据请求将它们反刍。

您粘贴的代码来自非常 的旧库,该库对Content-Type headers 的实现很差。如果在主要 e-learning 创作工具之一的内容的相对较旧版本以外的任何地方发现此代码,则应更新它以使用 TinCanJS 的最新版本并改进内容类型处理。

就在 Rails 上完成这项工作而言,抱歉,我没有那么多经验。大概有一个开关或其他东西可以关闭自动请求 body 解析,至少我用过的大多数其他框架都是这样。