我目前正在使用Google Places API以获得一些舒适性,但我遇到了一个让我有点困惑的问题,我希望有人能在这里纠正我。我正在对本地代理服务器进行API调用,到目前为止,除了我尝试为特定业务拉取图像外,其他一切都正常。
我已经在控制台上记录了GET请求URL的每个单独部分,以确保它连接正确,并且在这方面看起来都是正确的(我能够将其直接粘贴到浏览器中并获得预期的结果)。我有一种预感,这是一个一般性的代码问题,并不是特定于Places API本身的问题,但对此有任何见解都将非常感谢。来自代理服务器的终端错误(似乎不是很有用,但其他人可能会在这里识别一些我没有识别的东西):
未定义:1����^
语法错误:JSON中位置0处的意外标记�
前端代码:
function makeAPICall(url) {
return fetch(url);
}
makeAPICall(`http://localhost:5000/places/${searchString}`)
.then(response => {
return response.json();
})
.then(data => {
responseObject = data.results;
renderResult(responseObject[10]);
return responseObject[10];
})
.then(responseObject => {
makeAPICall(`http://localhost:5000/place/image/${responseObject.photos[0].photo_reference}`)
.then(response => {
return response.json();
})
.then(photoData => {
console.log(photoData);
});
});
代理代码(减去与问题无关的工作路径):
require('dotenv').config({path: '../.env'});
const express = require('express');
const request = require('request');
const GOOGLE_API_KEY = process.env.API_KEY;
const placesImgURL = 'https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=';
const app = express();
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
});
app.get('/place/image/:query', (req, res) => {
request(
{ url: `${placesImgURL}${req.params.query}&key=${GOOGLE_API_KEY}` },
(error, response, body) => {
if (error || response.statusCode !== 200) {
console.log(response);
}
res.json(JSON.parse(body));
}
)
});
const PORT = process.env.PORT || 4000;
app.listen(PORT, () => console.log(`listening on ${PORT}`));
更新:
触发错误的服务器代码行为:
res.json(JSON.parse(body));
开发工具内的网络调用屏幕截图:
当控制台记录抛出错误的行时,我得到以下信息(公平警告,这是完整的日志,并且非常长):
ServerResponse {
_events: { finish: [Function: bound resOnFinish] },
_eventsCount: 1,
_maxListeners: undefined,
output: [],
outputEncodings: [],
outputCallbacks: [],
outputSize: 0,
writable: true,
_last: false,
chunkedEncoding: false,
shouldKeepAlive: true,
useChunkedEncodingByDefault: true,
sendDate: true,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: 22631,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
socket:
Socket {
connecting: false,
_hadError: false,
_handle:
TCP {
reading: true,
onread: [Function: onStreamRead],
onconnection: null,
_consumed: true,
[Symbol(owner)]: [Circular] },
_parent: null,
_host: null,
_readableState:
ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: null,
pipesCount: 0,
flowing: true,
ended: false,
endEmitted: false,
reading: true,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
emitClose: false,
destroyed: false,
defaultEncoding: 'utf8',
awaitDrain: 0,
readingMore: false,
decoder: null,
encoding: null },
readable: true,
_events:
{ end: [Array],
drain: [Array],
timeout: [Function: socketOnTimeout],
data: [Function: bound socketOnData],
error: [Function: socketOnError],
close: [Array],
resume: [Function: onSocketResume],
pause: [Function: onSocketPause] },
_eventsCount: 8,
_maxListeners: undefined,
_writableState:
WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: false,
needDrain: true,
ending: false,
ended: false,
finished: false,
destroyed: false,
decodeStrings: false,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: false,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
bufferedRequest: null,
lastBufferedRequest: null,
pendingcb: 3,
prefinished: false,
errorEmitted: false,
emitClose: false,
bufferedRequestCount: 0,
corkedRequestsFree: [Object] },
writable: true,
allowHalfOpen: true,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server:
Server {
_events: [Object],
_eventsCount: 2,
_maxListeners: undefined,
_connections: 1,
_handle: [TCP],
_usingWorkers: false,
_workers: [],
_unref: false,
allowHalfOpen: true,
pauseOnConnect: false,
httpAllowHalfOpen: false,
timeout: 120000,
keepAliveTimeout: 5000,
_pendingResponseData: 0,
maxHeadersCount: null,
_connectionKey: '6::::5000',
[Symbol(IncomingMessage)]: [Function],
[Symbol(ServerResponse)]: [Function],
[Symbol(asyncId)]: 5 },
_server:
Server {
_events: [Object],
_eventsCount: 2,
_maxListeners: undefined,
_connections: 1,
_handle: [TCP],
_usingWorkers: false,
_workers: [],
_unref: false,
allowHalfOpen: true,
pauseOnConnect: false,
httpAllowHalfOpen: false,
timeout: 120000,
keepAliveTimeout: 5000,
_pendingResponseData: 0,
maxHeadersCount: null,
_connectionKey: '6::::5000',
[Symbol(IncomingMessage)]: [Function],
[Symbol(ServerResponse)]: [Function],
[Symbol(asyncId)]: 5 },
timeout: 120000,
parser:
HTTPParser {
'0': [Function: parserOnHeaders],
'1': [Function: parserOnHeadersComplete],
'2': [Function: parserOnBody],
'3': [Function: parserOnMessageComplete],
'4': [Function: bound onParserExecute],
_headers: [],
_url: '',
_consumed: true,
socket: [Circular],
incoming: [IncomingMessage],
outgoing: null,
maxHeaderPairs: 2000,
onIncoming: [Function: bound parserOnIncoming] },
on: [Function: socketOnWrap],
_paused: false,
_httpMessage: [Circular],
[Symbol(asyncId)]: 8,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]:
Timeout {
_called: false,
_idleTimeout: 120000,
_idlePrev: [TimersList],
_idleNext: [TimersList],
_idleStart: 6746,
_onTimeout: [Function: bound ],
_timerArgs: undefined,
_repeat: null,
_destroyed: false,
[Symbol(unrefed)]: true,
[Symbol(asyncId)]: 9,
[Symbol(triggerId)]: 8 },
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0 },
connection:
Socket {
connecting: false,
_hadError: false,
_handle:
TCP {
reading: true,
onread: [Function: onStreamRead],
onconnection: null,
_consumed: true,
[Symbol(owner)]: [Circular] },
_parent: null,
_host: null,
_readableState:
ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: null,
pipesCount: 0,
flowing: true,
ended: false,
endEmitted: false,
reading: true,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
emitClose: false,
destroyed: false,
defaultEncoding: 'utf8',
awaitDrain: 0,
readingMore: false,
decoder: null,
encoding: null },
readable: true,
_events:
{ end: [Array],
drain: [Array],
timeout: [Function: socketOnTimeout],
data: [Function: bound socketOnData],
error: [Function: socketOnError],
close: [Array],
resume: [Function: onSocketResume],
pause: [Function: onSocketPause] },
_eventsCount: 8,
_maxListeners: undefined,
_writableState:
WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: false,
needDrain: true,
ending: false,
ended: false,
finished: false,
destroyed: false,
decodeStrings: false,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: false,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
bufferedRequest: null,
lastBufferedRequest: null,
pendingcb: 3,
prefinished: false,
errorEmitted: false,
emitClose: false,
bufferedRequestCount: 0,
corkedRequestsFree: [Object] },
writable: true,
allowHalfOpen: true,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server:
Server {
_events: [Object],
_eventsCount: 2,
_maxListeners: undefined,
_connections: 1,
_handle: [TCP],
_usingWorkers: false,
_workers: [],
_unref: false,
allowHalfOpen: true,
pauseOnConnect: false,
httpAllowHalfOpen: false,
timeout: 120000,
keepAliveTimeout: 5000,
_pendingResponseData: 0,
maxHeadersCount: null,
_connectionKey: '6::::5000',
[Symbol(IncomingMessage)]: [Function],
[Symbol(ServerResponse)]: [Function],
[Symbol(asyncId)]: 5 },
_server:
Server {
_events: [Object],
_eventsCount: 2,
_maxListeners: undefined,
_connections: 1,
_handle: [TCP],
_usingWorkers: false,
_workers: [],
_unref: false,
allowHalfOpen: true,
pauseOnConnect: false,
httpAllowHalfOpen: false,
timeout: 120000,
keepAliveTimeout: 5000,
_pendingResponseData: 0,
maxHeadersCount: null,
_connectionKey: '6::::5000',
[Symbol(IncomingMessage)]: [Function],
[Symbol(ServerResponse)]: [Function],
[Symbol(asyncId)]: 5 },
timeout: 120000,
parser:
HTTPParser {
'0': [Function: parserOnHeaders],
'1': [Function: parserOnHeadersComplete],
'2': [Function: parserOnBody],
'3': [Function: parserOnMessageComplete],
'4': [Function: bound onParserExecute],
_headers: [],
_url: '',
_consumed: true,
socket: [Circular],
incoming: [IncomingMessage],
outgoing: null,
maxHeaderPairs: 2000,
onIncoming: [Function: bound parserOnIncoming] },
on: [Function: socketOnWrap],
_paused: false,
_httpMessage: [Circular],
[Symbol(asyncId)]: 8,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]:
Timeout {
_called: false,
_idleTimeout: 120000,
_idlePrev: [TimersList],
_idleNext: [TimersList],
_idleStart: 6746,
_onTimeout: [Function: bound ],
_timerArgs: undefined,
_repeat: null,
_destroyed: false,
[Symbol(unrefed)]: true,
[Symbol(asyncId)]: 9,
[Symbol(triggerId)]: 8 },
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0 },
_header:
'HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Content-Length: 22631
ETag: W/"5867-c3Fodr1eSCA3vlKX+kDMgudDONQ"
Date: Wed, 26 Aug 2020 18:14:27 GMT
Connection: keep-alive
',
_onPendingData: [Function: bound updateOutgoingData],
_sent100: false,
_expect_continue: false,
req:
IncomingMessage {
_readableState:
ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: null,
pipesCount: 0,
flowing: null,
ended: true,
endEmitted: false,
reading: false,
sync: true,
needReadable: false,
emittedReadable: true,
readableListening: false,
resumeScheduled: false,
emitClose: true,
destroyed: false,
defaultEncoding: 'utf8',
awaitDrain: 0,
readingMore: true,
decoder: null,
encoding: null },
readable: true,
_events: {},
_eventsCount: 0,
_maxListeners: undefined,
socket:
Socket {
connecting: false,
_hadError: false,
_handle: [TCP],
_parent: null,
_host: null,
_readableState: [ReadableState],
readable: true,
_events: [Object],
_eventsCount: 8,
_maxListeners: undefined,
_writableState: [WritableState],
writable: true,
allowHalfOpen: true,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: [Server],
_server: [Server],
timeout: 120000,
parser: [HTTPParser],
on: [Function: socketOnWrap],
_paused: false,
_httpMessage: [Circular],
[Symbol(asyncId)]: 8,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]:
Timeout {
_called: false,
_idleTimeout: 120000,
_idlePrev: [TimersList],
_idleNext: [TimersList],
_idleStart: 6746,
_onTimeout: [Function: bound ],
_timerArgs: undefined,
_repeat: null,
_destroyed: false,
[Symbol(unrefed)]: true,
[Symbol(asyncId)]: 9,
[Symbol(triggerId)]: 8 },
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0 },
connection:
Socket {
connecting: false,
_hadError: false,
_handle: [TCP],
_parent: null,
_host: null,
_readableState: [ReadableState],
readable: true,
_events: [Object],
_eventsCount: 8,
_maxListeners: undefined,
_writableState: [WritableState],
writable: true,
allowHalfOpen: true,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: [Server],
_server: [Server],
timeout: 120000,
parser: [HTTPParser],
on: [Function: socketOnWrap],
_paused: false,
_httpMessage: [Circular],
[Symbol(asyncId)]: 8,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]:
Timeout {
_called: false,
_idleTimeout: 120000,
_idlePrev: [TimersList],
_idleNext: [TimersList],
_idleStart: 6746,
_onTimeout: [Function: bound ],
_timerArgs: undefined,
_repeat: null,
_destroyed: false,
[Symbol(unrefed)]: true,
[Symbol(asyncId)]: 9,
[Symbol(triggerId)]: 8 },
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0 },
httpVersionMajor: 1,
httpVersionMinor: 1,
httpVersion: '1.1',
complete: true,
headers:
{ host: 'localhost:5000',
connection: 'keep-alive',
'user-agent':
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36',
accept: '*/*',
origin: 'http://localhost:3000',
'sec-fetch-site': 'same-site',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
referer: 'http://localhost:3000/',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'en-US,en;q=0.9',
'if-none-match': 'W/"5868-+iRV2Q1kdgam9TbgiDgKID9Vs1s"' },
rawHeaders:
[ 'Host',
'localhost:5000',
'Connection',
'keep-alive',
'User-Agent',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36',
'Accept',
'*/*',
'Origin',
'http://localhost:3000',
'Sec-Fetch-Site',
'same-site',
'Sec-Fetch-Mode',
'cors',
'Sec-Fetch-Dest',
'empty',
'Referer',
'http://localhost:3000/',
'Accept-Encoding',
'gzip, deflate, br',
'Accept-Language',
'en-US,en;q=0.9',
'If-None-Match',
'W/"5868-+iRV2Q1kdgam9TbgiDgKID9Vs1s"' ],
trailers: {},
rawTrailers: [],
aborted: false,
upgrade: false,
url: '/places/restaurants+near%20me',
method: 'GET',
statusCode: null,
statusMessage: null,
client:
Socket {
connecting: false,
_hadError: false,
_handle: [TCP],
_parent: null,
_host: null,
_readableState: [ReadableState],
readable: true,
_events: [Object],
_eventsCount: 8,
_maxListeners: undefined,
_writableState: [WritableState],
writable: true,
allowHalfOpen: true,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: [Server],
_server: [Server],
timeout: 120000,
parser: [HTTPParser],
on: [Function: socketOnWrap],
_paused: false,
_httpMessage: [Circular],
[Symbol(asyncId)]: 8,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]:
Timeout {
_called: false,
_idleTimeout: 120000,
_idlePrev: [TimersList],
_idleNext: [TimersList],
_idleStart: 6746,
_onTimeout: [Function: bound ],
_timerArgs: undefined,
_repeat: null,
_destroyed: false,
[Symbol(unrefed)]: true,
[Symbol(asyncId)]: 9,
[Symbol(triggerId)]: 8 },
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0 },
_consuming: false,
_dumped: false,
next: [Function: next],
baseUrl: '',
originalUrl: '/places/restaurants+near%20me',
_parsedUrl:
Url {
protocol: null,
slashes: null,
auth: null,
host: null,
port: null,
hostname: null,
hash: null,
search: null,
query: null,
pathname: '/places/restaurants+near%20me',
path: '/places/restaurants+near%20me',
href: '/places/restaurants+near%20me',
_raw: '/places/restaurants+near%20me' },
params: { query: 'restaurants+near me' },
query: {},
res: [Circular],
route:
Route { path: '/places/:query', stack: [Array], methods: [Object] } },
locals: {},
statusMessage: 'OK',
statusCode: 200,
[Symbol(isCorked)]: false,
[Symbol(outHeadersKey)]:
{ 'x-powered-by': [ 'X-Powered-By', 'Express' ],
'access-control-allow-origin': [ 'Access-Control-Allow-Origin', '*' ],
'content-type': [ 'Content-Type', 'application/json; charset=utf-8' ],
'content-length': [ 'Content-Length', '22631' ],
etag: [ 'ETag', 'W/"5867-c3Fodr1eSCA3vlKX+kDMgudDONQ"' ] } }
_http_outgoing.js:470
throw new ERR_HTTP_HEADERS_SENT('set');
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:470:11)
at ServerResponse.header (/Users/tyleranyan/Documents/api-practice/places/node_modules/express/lib/response.js:771:10)
at ServerResponse.send (/Users/tyleranyan/Documents/api-practice/places/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/Users/tyleranyan/Documents/api-practice/places/node_modules/express/lib/response.js:267:15)
at Request.request [as _callback] (/Users/tyleranyan/Documents/api-practice/places/proxy/server.js:25:11)
at Request.self.callback (/Users/tyleranyan/Documents/api-practice/places/node_modules/request/request.js:185:22)
at Request.emit (events.js:182:13)
at Request.<anonymous> (/Users/tyleranyan/Documents/api-practice/places/node_modules/request/request.js:1154:10)
at Request.emit (events.js:182:13)
at IncomingMessage.<anonymous> (/Users/tyleranyan/Documents/api-practice/places/node_modules/request/request.js:1076:12)
这里的问题是request库似乎已弃用。如果您切换到其他代码,如axios,则基于您自己的代码可以正常运行:
const express = require('express')
const axios = require('axios')
const url = "https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=CnRtAAAATLZNl354RwP_9UKbQ_5Psy40texXePv4oAlgP4qNEkdIrkyse7rPXYGd9D_Uj1rVsQdWT4oRz4QrYAJNpFX7rzqqMlZw2h2E2y5IKMUZ7ouD_SlcHxYq1yL4KbKUv3qtWgTK0A6QbGh87GB3sscrHRIQiG2RrmU_jF4tENr9wGS_YxoUSSDrYjWmrNfeEHSGSc3FyhNLlBU&key=YOUR_API_KEY"
const getData = async (url) => {
try {
const response = await axios.get(url)
const data = response.data
console.log('data', response.data)
} catch (error) {
console.log('error', error)
}
}
const app = express()
const port = 3000
app.get('/', async (req, res) => {
res.send(await getData(url))
})
app.listen(port, () => {})
输出:
Response GET / status=200
"data"
"����u0000u0010JFIFu0000u0001u00…01b`J+]�Ǥ�%�„c����8�u001fbu0017/��..."
响应也是image;不要在后端发送它。不过,还有client-side service。