我在PHP中使用Guzzle(v6.1.1)向服务器发出POST请求。它工作正常。我正在添加一些日志记录功能来记录发送和接收的内容,我无法弄清楚如何获取Guzzle发送到服务器的数据。我可以很好地获得响应,但如何获取已发送数据? (这将是JSON字符串。)
以下是我的代码的相关部分:
$client = new GuzzleHttp\Client(['base_uri' => $serviceUrlPayments ]);
try {
$response = $client->request('POST', 'Charge', [
'auth' => [$securenetId, $secureKey],
'json' => [ "amount" => $amount,
"paymentVaultToken" => array(
"customerId" => $customerId,
"paymentMethodId" => $token,
"publicKey" => $publicKey
),
"extendedInformation" => array(
"typeOfGoods" => $typeOfGoods,
"userDefinedFields" => $udfs,
"notes" => $Notes
),
'developerApplication'=> $developerApplication
]
]);
} catch (ServerErrorResponseException $e) {
echo (string) $e->getResponse()->getBody();
}
echo $response->getBody(); // THIS CORRECTLY SHOWS THE SERVER RESPONSE
echo $client->getBody(); // This doesn't work
echo $client->request->getBody(); // nor does this
任何帮助将不胜感激。我确实试图在Guzzle源代码中查找类似于getBody()的函数,该函数可以处理请求,但我不是PHP专家,所以我没有提出任何有用的信息。我也经常搜索Google,但发现只有人在讨论从服务器上获取响应,我没有遇到任何问题。
答案 0 :(得分:12)
您可以通过创建Middleware来完成这项工作。
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use Psr\Http\Message\RequestInterface;
$stack = HandlerStack::create();
// my middleware
$stack->push(Middleware::mapRequest(function (RequestInterface $request) {
$contentsRequest = (string) $request->getBody();
//var_dump($contentsRequest);
return $request;
}));
$client = new Client([
'base_uri' => 'http://www.example.com/api/',
'handler' => $stack
]);
$response = $client->request('POST', 'itemupdate', [
'auth' => [$username, $password],
'json' => [
"key" => "value",
"key2" => "value",
]
]);
然而,这是在收到回复之前触发的。你可能想做这样的事情:
$stack->push(function (callable $handler) {
return function (RequestInterface $request, array $options) use ($handler) {
return $handler($request, $options)->then(
function ($response) use ($request) {
// work here
$contentsRequest = (string) $request->getBody();
//var_dump($contentsRequest);
return $response;
}
);
};
});
答案 1 :(得分:7)
使用Guzzle 6.2。
在过去的几天里,我一直在努力解决这一问题,同时尝试构建一种方法来审核与不同API的HTTP交互。在我的情况下,解决方案是简单地倒退请求正文。
请求的正文实际上是作为stream实现的。因此,发送请求时,Guzzle从流中读取。读取完整的流会将流的内部指针移到末尾。因此,在发出请求后调用getContents()
时,内部指针已经位于流的末尾,并且不返回任何内容。
解决方案?将指针倒退到开头,然后再次读取流。
<?php
// ...
$body = $request->getBody();
echo $body->getContents(); // -->nothing
// Rewind the stream
$body->rewind();
echo $body->getContents(); // -->The request body :)
答案 2 :(得分:1)
您可以通过执行
来重现请求创建的数据字符串public class ArticleListActivity extends ActionBarActivity implements LoaderManager.LoaderCallbacks<Cursor> {
private int mFadeSleepTime = 16000;
private int mWordBuffer = 200;//number of words we will display at a time
private int mMaxChars = 0;
private int mTotalPages = 0;
private int mCurrentPage = 0;
private Toolbar mToolbar;
private SwipeRefreshLayout mSwipeRefreshLayout;
private RecyclerView mRecyclerView;
private int mTextPostion = 0;
public int mPagePadding = 10;
Animation fadeIn = new AlphaAnimation(0.0f, 1.0f);
Animation fadeOut = new AlphaAnimation(1.0f, 0.0f);
Animation mNewspaperClipSelectedAnimation;
Animation mNewspaperClipSlideDownAnimation;
Adapter mAdapter;
String mbodyText;
boolean mEndsInSpace = true;
CoordinatorLayout mMainContainer;
private Thread mTextSwitcherThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_article_list);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
final View toolbarContainerView = findViewById(R.id.toolbar_container);
mMainContainer = (CoordinatorLayout) findViewById(R.id.main_coordinator_layout);
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
fadeIn.setDuration(2000);
fadeOut.setDuration(1000);
mRecyclerView.setItemAnimator(null);
mNewspaperClipSelectedAnimation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.newspaper_selected_anim);
mNewspaperClipSlideDownAnimation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.newspaper_unselected_stories_slide_out);
fadeOut.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
final int index = i;
View v = mRecyclerView.getChildAt(i);
v.findViewById(R.id.article_body).startAnimation(fadeIn);
mRecyclerView.invalidate();
ArticleListActivity.this.runOnUiThread(new Runnable() {
public void run() {
mAdapter.notifyItemChanged(index);
}
});
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
getLoaderManager().initLoader(0, null, this);
if (savedInstanceState == null) {
refresh();
}
setTextFadeThread();
}
private void setTextFadeThread(){
mTextSwitcherThread = new Thread() {
@Override
public void run() {
try {
while (true) {
sleep(mFadeSleepTime);
mTextPostion += mWordBuffer;
while (mEndsInSpace) {
if (mbodyText.charAt(mTextPostion) != ' ') {
mTextPostion += 1;
} else {
mEndsInSpace = false;
}
}
if (mTextPostion > mMaxChars - mWordBuffer) {
mTextPostion = 0;
mCurrentPage = -1;
}
ArticleListActivity.this.runOnUiThread(new Runnable() {
public void run() {
for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
View v = mRecyclerView.getChildAt(i);
v.findViewById(R.id.article_body).startAnimation(fadeOut);
}
mCurrentPage = mCurrentPage + 1;
}
});
mEndsInSpace = true;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
mTextSwitcherThread.start();
}
private void addStoryToLibrary(){
}
private void refresh() {
startService(new Intent(this, UpdaterService.class));
}
@Override
protected void onStart() {
super.onStart();
registerReceiver(mRefreshingReceiver, new IntentFilter(UpdaterService.BROADCAST_ACTION_STATE_CHANGE));
}
@Override
protected void onStop() {
super.onStop();
unregisterReceiver(mRefreshingReceiver);
}
private boolean mIsRefreshing = false;
private BroadcastReceiver mRefreshingReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (UpdaterService.BROADCAST_ACTION_STATE_CHANGE.equals(intent.getAction())) {
mIsRefreshing = intent.getBooleanExtra(UpdaterService.EXTRA_REFRESHING, false);
updateRefreshingUI();
}
}
};
private void updateRefreshingUI() {
mSwipeRefreshLayout.setRefreshing(mIsRefreshing);
}
@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
return ArticleLoader.newAllArticlesInstance(this);
}
@Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
mAdapter = new Adapter(this,cursor);
mAdapter.setHasStableIds(true);
mRecyclerView.setAdapter(mAdapter);
int columnCount = getResources().getInteger(R.integer.list_column_count);
StaggeredGridLayoutManager sglm = new StaggeredGridLayoutManager(columnCount, StaggeredGridLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(sglm);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
mRecyclerView.setAdapter(null);
}
private class Adapter extends RecyclerView.Adapter<ViewHolder> {
private Cursor mCursor;
private Context mContext;
public Adapter(Context context,Cursor cursor) {
mContext = context;
mCursor = cursor;
}
@Override
public long getItemId(int position) {
mCursor.moveToPosition(position);
return mCursor.getLong(ArticleLoader.Query._ID);
}
@Override
public ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
View view = getLayoutInflater().inflate(R.layout.list_item_article, parent, false);
final ViewHolder vh = new ViewHolder(view);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View view) {
mTextSwitcherThread.interrupt(); // interrupt text cycle thread as we go to detail views
for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
View v = mRecyclerView.getChildAt(i);
if(v != view) {
v.findViewById(R.id.article_body).startAnimation(fadeOut);
v.setAnimation(mNewspaperClipSlideDownAnimation);
v.startAnimation(mNewspaperClipSlideDownAnimation);
}
}
mNewspaperClipSlideDownAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
View v = mRecyclerView.getChildAt(i);
if(v != view) {
v.setVisibility(View.INVISIBLE);
}
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
ExpandingCardViewAnimation animation = new ExpandingCardViewAnimation(getApplicationContext(),parent,view);
animation.configureAnimation();
view.setAnimation(mNewspaperClipSelectedAnimation);
view.startAnimation(mNewspaperClipSelectedAnimation);
mNewspaperClipSlideDownAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
view.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
view.getViewTreeObserver().removeOnPreDrawListener(this);
startPostponedEnterTransition(vh);
return true;
}
});
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
});
return vh;
}
public void startPostponedEnterTransition(ViewHolder vh){
String transitionName = getString(R.string.transition_list_item);
Activity activity = (Activity) mContext;
ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, mRecyclerView,transitionName);
ActivityCompat.startActivity(activity, new Intent(Intent.ACTION_VIEW, ItemsContract.Items.buildItemUri(getItemId(vh.getAdapterPosition()))), options.toBundle());
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
mCursor.moveToPosition(position);
holder.titleView.setText(mCursor.getString(ArticleLoader.Query.TITLE));
holder.subtitleView.setText(Html.fromHtml(
DateUtils.getRelativeTimeSpanString(
mCursor.getLong(ArticleLoader.Query.PUBLISHED_DATE),
System.currentTimeMillis(), DateUtils.HOUR_IN_MILLIS,
DateUtils.FORMAT_ABBREV_ALL).toString()
+ " by <font color='#ffffff'>"
+ mCursor.getString(ArticleLoader.Query.AUTHOR)
+ "</font>"));
holder.thumbnailView.setImageUrl(
mCursor.getString(ArticleLoader.Query.THUMB_URL),
ImageLoaderHelper.getInstance(ArticleListActivity.this).getImageLoader());
holder.thumbnailView.setAspectRatio(mCursor.getFloat(ArticleLoader.Query.ASPECT_RATIO));
mbodyText = mCursor.getString(ArticleLoader.Query.BODY);
mMaxChars = mbodyText.length();
mTotalPages = mMaxChars/mWordBuffer;
holder.bodyView.setText(mbodyText.substring(mTextPostion, mTextPostion + mWordBuffer));
holder.pagesview.removeAllViews();
for(int i = 0; i < mTotalPages; i++){
TextView mPageText = new TextView(getApplicationContext());
mPageText.setLayoutParams(new RelativeLayout.LayoutParams(RecyclerView.LayoutParams.WRAP_CONTENT, RecyclerView.LayoutParams.WRAP_CONTENT));
mPageText.setText(Integer.toString(i + 1));
mPageText.setPadding(mPagePadding,mPagePadding,mPagePadding,0);
mPageText.setTextSize(19);
if(mCurrentPage == i)
mPageText.setTextColor(getResources().getColor(R.color.highlited_page_color));
else
mPageText.setTextColor(getResources().getColor(R.color.blue_page_number_color));
mPageText.setTag(i);
mPageText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for (int i = 0; i < mTotalPages; i++) {
TextView pageView = (TextView) holder.pagesview.getChildAt(i);
pageView.setTextColor(getResources().getColor(R.color.blue_page_number_color));
}
((TextView)v).setTextColor(getResources().getColor(R.color.highlited_page_color));
mTextPostion = (int) v.getTag() * mWordBuffer;
mCurrentPage = (int) v.getTag();
v.startAnimation(fadeOut);
}
});
holder.pagesview.addView(mPageText);
}
holder.libraryfabbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addStoryToLibrary();
Snackbar addToLibrarySnackbar = Snackbar.make(mMainContainer,getString(R.string.story_added_to_library),Snackbar.LENGTH_LONG);
addToLibrarySnackbar.show();
}
});
holder.facebooklikebutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addStoryToLibrary();
Snackbar addToLibrarySnackbar = Snackbar.make(mMainContainer,getString(R.string.story_added_to_library),Snackbar.LENGTH_LONG);
addToLibrarySnackbar.show();
}
});
}
@Override
public int getItemCount() {
return mCursor.getCount();
}
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public DynamicHeightNetworkImageView thumbnailView;
public TextView titleView;
public TextView subtitleView;
public TextView bodyView;
public LinearLayout pagesview;
public ImageButton libraryfabbutton;
public ImageButton facebooklikebutton;
public ViewHolder(final View view) {
super(view);
thumbnailView = (DynamicHeightNetworkImageView) view.findViewById(R.id.thumbnail);
titleView = (TextView) view.findViewById(R.id.article_title);
subtitleView = (TextView) view.findViewById(R.id.article_subtitle);
bodyView = (TextView) view.findViewById(R.id.article_body);
pagesview = (LinearLayout) view.findViewById(R.id.newspaper_clip_pages);
libraryfabbutton = (ImageButton) view.findViewById(R.id.add_to_lib_fab);
facebooklikebutton = (ImageButton) view.findViewById(R.id.face_book_like_button);
}
}
}
这会将您的数据输出为JSON字符串。
http://php.net/manual/fr/function.json-encode.php
上的文档修改强>
Guzzle有一个$data = array(
"key" => "value",
"key2" => "value",
);
$response = $client->request('POST', 'itemupdate', [
'auth' => [$username, $password],
'json' => $data,
]);
// ...
echo json_encode($data);
和一个Request
类(以及许多其他类)
Response
实际上有一个Request
方法,该方法将包含您getQuery()
的对象作为私有对象返回,与所有其他成员相同。
你也无法访问它。
这就是为什么我认为手动编码它是更容易的解决方案。
如果你想知道Guzzle做了什么,它还有一个data
类来转换数据并在请求中发送它。
答案 3 :(得分:1)
我的 Laravel 5.7版本的解决方案:
MessageFormatter可用于变量替换,请参见:https://github.com/guzzle/guzzle/blob/master/src/MessageFormatter.php
$stack = HandlerStack::create();
$stack->push(
Middleware::log(
Log::channel('single'),
new MessageFormatter('Req Body: {request}')
)
);
$client = new Client();
$response = $client->request(
'POST',
'https://url.com/go',
[
'headers' => [
"Content-Type" => "application/json",
'Authorization' => 'Bearer 123'
],
'json' => $menu,
'handler' => $stack
]
);