我一直在尝试从Business Central连接和检索数据列表。Web服务已从BC公开,OData链接正常工作并显示"文章"中数据的JSON。我正在尝试使用NTLM使用NodeJS使用该服务(我还尝试了基本身份验证,但仍然存在相同的问题。请在下面找到负责使用BC Web服务的文件,后面跟着401错误。我已经将NTLM配置所需的所有信息存储在. env文件中,我确实尝试过对它们进行硬编码,但出现了相同的问题
const express = require("express");
const axios = require("axios");
const router = express.Router();
const ntlm = require("express-ntlm");
//const Article = require("../models/Articles.js");
const domain = process.env.DOMAIN;
const username = process.env.USERNAME;
const password = process.env.PASSWORD;
// Define auth function
const auth = ntlm({
debug: console.log,
domain,
username,
password,
ntlm_version: 2,
reconnect: true,
send_401: function (res) {
res.sendStatus(401);
},
badrequest: function (res) {
res.sendStatus(400);
},
});
// Get customer data from Business Central
async function getArticlesFromBC() {
try {
const options = {
auth: {
username,
password,
workstation: process.env.WORKSTATION,
domain,
},
};
const companyId = "CRONUS France S.A.";
const encodedCompanyId = encodeURIComponent(companyId);
const url = `http://${process.env.SERVER}:7048/BC210/ODataV4/Company('${encodedCompanyId}')/ItemListec`;
const response = await axios.get(url, options);
return response.data;
} catch (error) {
console.error(error);
throw new Error("Error retrieving articles data from Business Central");
}
}
// Route to get article data
router.get("/", auth, async (req, res) => {
try {
const user = req.ntlm;
console.log(user);
let articles = await getArticlesFromBC();
res.json(articles);
} catch (error) {
console.error(error);
res
.status(500)
.send("Error retrieving articles data from Business Central");
}
});
module.exports = router;
- 说明**
- 这是一个auth函数,它将使用. env中设置的变量对用户进行身份验证,以便访问BC端点
// Define auth function
const auth = ntlm({
debug: console.log,
domain,
username,
password,
ntlm_version: 2,
reconnect: true,
send_401: function (res) {
res.sendStatus(401);
},
badrequest: function (res) {
res.sendStatus(400);
},
});
- 这是连接到端点URL并返回JSON文件的函数,这是触发错误的地方
// Get article data from Business Central
async function getArticlesFromBC() {
try {
const options = {
auth: {
username,
password,
workstation: process.env.WORKSTATION,
domain,
},
};
const companyId = "CRONUS France S.A.";
const encodedCompanyId = encodeURIComponent(companyId);
const url = `http://${process.env.SERVER}:7048/BC210/ODataV4/Company('${encodedCompanyId}')/ItemListec`;
const response = await axios.get(url, options);
return response.data;
} catch (error) {
console.error(error);
throw new Error("Error retrieving articles data from Business Central");
}
}
- 这是访问nodejs api的路径
// Route to get article data
router.get("/", auth, async (req, res) => {
try {
const user = req.ntlm;
console.log(user);
let articles = await getArticlesFromBC();
res.json(articles);
} catch (error) {
console.error(error);
res
.status(500)
.send("Error retrieving articles data from Business Central");
}
});
- 这是401错误json,您可以在开头看到NTLM成功进行了身份验证,但随后在get函数中抛出了catch块**
[express-ntlm] No Authorization header present
[express-ntlm] No domaincontroller was specified, all Authentication messages are valid.
{
DomainName: 'DESKTOP-1EF91E4',
UserName: 'ahmed',
Workstation: 'DESKTOP-1EF91E4',
Authenticated: true
}
AxiosError: Request failed with status code 401
at settle (D:\ESPRIT\5eme\PFE\B2B-ERP-MERN-App\node_modules\axios\dist\node\axios.cjs:1900:12)
at IncomingMessage.handleStreamEnd (D:\ESPRIT\5eme\PFE\B2B-ERP-MERN-App\node_modules\axios\dist\node\axios.cjs:2944:11)
at IncomingMessage.emit (events.js:412:35)
at endReadableNT (internal/streams/readable.js:1317:12)
at processTicksAndRejections (internal/process/task_queues.js:82:21) {
code: 'ERR_BAD_REQUEST',
config: {
transitional: {
silentJSONParsing: true,
forcedJSONParsing: true,
clarifyTimeoutError: false
},
adapter: [ 'xhr', 'http' ],
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
env: { FormData: [Function], Blob: null },
validateStatus: [Function: validateStatus],
headers: AxiosHeaders {
Accept: 'application/json, text/plain, */*',
'User-Agent': 'axios/1.3.3',
'Accept-Encoding': 'gzip, compress, deflate, br'
},
auth: {
username: 'ahmed',
password: undefined,
workstation: 'DESKTOP-1EF91E4',
domain: undefined
},
method: 'get',
url: "http://desktop-1ef91e4:7048/BC210/ODataV4/Company('CRONUS%20France%20S.A.')/ItemListec",
data: undefined
},
request: <ref *1> ClientRequest {
_events: [Object: null prototype] {
abort: [Function (anonymous)],
aborted: [Function (anonymous)],
connect: [Function (anonymous)],
error: [Function (anonymous)],
socket: [Function (anonymous)],
timeout: [Function (anonymous)],
prefinish: [Function: requestOnPrefinish]
},
_eventsCount: 7,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
destroyed: false,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: false,
_defaultKeepAlive: true,
useChunkedEncodingByDefault: false,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: 0,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
socket: Socket {
connecting: false,
_hadError: false,
_parent: null,
_host: 'desktop-1ef91e4',
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 7,
_maxListeners: undefined,
_writableState: [WritableState],
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
parser: null,
_httpMessage: [Circular *1],
[Symbol(async_id_symbol)]: 465,
[Symbol(kHandle)]: [TCP],
[Symbol(kSetNoDelay)]: false,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: null,
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kCapture)]: false,
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0,
[Symbol(RequestTimeout)]: undefined
},
_header: "GET /BC210/ODataV4/Company('CRONUS%20France%20S.A.')/ItemListec HTTP/1.1\r\n" +
'Accept: application/json, text/plain, */*\r\n' +
'User-Agent: axios/1.3.3\r\n' +
'Accept-Encoding: gzip, compress, deflate, br\r\n' +
'Host: desktop-1ef91e4:7048\r\n' +
'Authorization: Basic YWhtZWQ6\r\n' +
'Connection: close\r\n' +
'\r\n',
_keepAliveTimeout: 0,
_onPendingData: [Function: noopPendingOutput],
agent: Agent {
_events: [Object: null prototype],
_eventsCount: 2,
_maxListeners: undefined,
defaultPort: 80,
protocol: 'http:',
options: [Object],
requests: {},
sockets: [Object],
freeSockets: {},
keepAliveMsecs: 1000,
keepAlive: false,
maxSockets: Infinity,
maxFreeSockets: 256,
scheduling: 'lifo',
maxTotalSockets: Infinity,
totalSocketCount: 1,
[Symbol(kCapture)]: false
},
socketPath: undefined,
method: 'GET',
maxHeaderSize: undefined,
insecureHTTPParser: undefined,
path: "/BC210/ODataV4/Company('CRONUS%20France%20S.A.')/ItemListec",
_ended: true,
res: IncomingMessage {
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 4,
_maxListeners: undefined,
socket: [Socket],
httpVersionMajor: 1,
httpVersionMinor: 1,
httpVersion: '1.1',
complete: true,
headers: [Object],
rawHeaders: [Array],
trailers: {},
rawTrailers: [],
aborted: false,
upgrade: false,
url: '',
method: null,
statusCode: 401,
statusMessage: 'Unauthorized',
client: [Socket],
_consuming: false,
_dumped: false,
req: [Circular *1],
responseUrl: "http://ahmed:@desktop-1ef91e4:7048/BC210/ODataV4/Company('CRONUS%20France%20S.A.')/ItemListec",
redirects: [],
[Symbol(kCapture)]: false,
[Symbol(RequestTimeout)]: undefined
},
aborted: false,
timeoutCb: null,
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
reusedSocket: false,
host: 'desktop-1ef91e4',
protocol: 'http:',
_redirectable: Writable {
_writableState: [WritableState],
_events: [Object: null prototype],
_eventsCount: 3,
_maxListeners: undefined,
_options: [Object],
_ended: true,
_ending: true,
_redirectCount: 0,
_redirects: [],
_requestBodyLength: 0,
_requestBodyBuffers: [],
_onNativeResponse: [Function (anonymous)],
_currentRequest: [Circular *1],
_currentUrl: "http://ahmed:@desktop-1ef91e4:7048/BC210/ODataV4/Company('CRONUS%20France%20S.A.')/ItemListec",
[Symbol(kCapture)]: false
},
[Symbol(kCapture)]: false,
[Symbol(kNeedDrain)]: false,
[Symbol(corked)]: 0,
[Symbol(kOutHeaders)]: [Object: null prototype] {
accept: [Array],
'user-agent': [Array],
'accept-encoding': [Array],
host: [Array],
authorization: [Array]
}
},
response: {
status: 401,
statusText: 'Unauthorized',
headers: AxiosHeaders {
'content-length': '0',
server: 'Microsoft-HTTPAPI/2.0',
'www-authenticate': 'Negotiate',
date: 'Thu, 16 Feb 2023 11:49:51 GMT',
connection: 'close'
},
config: {
transitional: [Object],
adapter: [Array],
transformRequest: [Array],
transformResponse: [Array],
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
env: [Object],
validateStatus: [Function: validateStatus],
headers: [AxiosHeaders],
auth: [Object],
method: 'get',
url: "http://desktop-1ef91e4:7048/BC210/ODataV4/Company('CRONUS%20France%20S.A.')/ItemListec",
data: undefined
},
request: <ref *1> ClientRequest {
_events: [Object: null prototype],
_eventsCount: 7,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
destroyed: false,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: false,
_defaultKeepAlive: true,
useChunkedEncodingByDefault: false,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: 0,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
socket: [Socket],
_header: "GET /BC210/ODataV4/Company('CRONUS%20France%20S.A.')/ItemListec HTTP/1.1\r\n" +
'Accept: application/json, text/plain, */*\r\n' +
'User-Agent: axios/1.3.3\r\n' +
'Accept-Encoding: gzip, compress, deflate, br\r\n' +
'Host: desktop-1ef91e4:7048\r\n' +
'Authorization: Basic YWhtZWQ6\r\n' +
'Connection: close\r\n' +
'\r\n',
_keepAliveTimeout: 0,
_onPendingData: [Function: noopPendingOutput],
agent: [Agent],
socketPath: undefined,
method: 'GET',
maxHeaderSize: undefined,
insecureHTTPParser: undefined,
path: "/BC210/ODataV4/Company('CRONUS%20France%20S.A.')/ItemListec",
_ended: true,
res: [IncomingMessage],
aborted: false,
timeoutCb: null,
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
reusedSocket: false,
host: 'desktop-1ef91e4',
protocol: 'http:',
_redirectable: [Writable],
[Symbol(kCapture)]: false,
[Symbol(kNeedDrain)]: false,
[Symbol(corked)]: 0,
[Symbol(kOutHeaders)]: [Object: null prototype]
},
data: ''
}
}
Error: Error retrieving articles data from Business Central
at getArticlesFromBC (D:\ESPRIT\5eme\PFE\B2B-ERP-MERN-App\routes\ArticleRoutes.js:44:11)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at async D:\ESPRIT\5eme\PFE\B2B-ERP-MERN-App\routes\ArticleRoutes.js:53:20
1条答案
按热度按时间3vpjnl9f1#
尽管它在postman中工作得很好(启用了服务器示例上的NTLM身份验证),express-ntlm似乎对用户进行了身份验证,但由于某种原因没有发送后续消息。我切换到httpntlm,它工作得很好,下面是节点API文件中的新代码: